算法基础数论
因数和质因数分解
质数判断
复杂度:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
const ll inf = 4e18, p = 998244353;
bool isprime(int x) {
if (x<2) return false;
for (int i = 2; i * i < x; ++i) {
if (x%i==0) return false;
}
return true;
}
int main() {
int n;
cin >> n;
cout << isprime(n);
}
分解因数
1 | int main() { |
质因数分解
1 | int main() { |
素数筛
1、埃氏筛法
复杂度:
使用bitset记录下标是否为素数,如:
0代表下标是素数未被筛除,1代表不是素数被筛除。
b[0]=1,b[1]=1,b[2]=0,b[3]=0
2和3均为素数,将其倍数标记为筛除,继续遍历以此类推1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using namespace std;
using ll = long long;
const int N = 2e6 + 10;
bitset<N> vis;
int main() {
int n;
cin >> n;
vis[0] = vis[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!vis[i])
// 从其最近的倍数开始,步长为i,筛掉i的倍数
// int j = i*i更好,2i会被2筛掉,3i会被3筛掉...
for (int j = 2 * i; j <= n; j += i)
vis[j] = 1;
}
for (int i = 1; i <= n; ++i)
if (!vis[i])
cout << i << ' ';
}
2、欧拉筛
一般埃氏筛能满足大多数要求,以后用到就补充。
GCD和LCM
唯一分解定理
自然数N可以唯一分解成几个数幂连乘的形式。
例如:
则
辗转相除法
已知
则
结合唯一分解定理则
代码实现gcd, lcm1
2
3
4
5
6
7ll gcd(ll a, ll b) {
return b==0 ? a : gcd(b, a%b);
}
ll lcm(ll a, ll b) {
// a*b/gcd(a,b)可能会溢出long long
return a/gcd(a, b) * b;
}
在numeric和万能头中也有实现,例如1
2
3
4
5
6
7
8
// 或
...
int main() {
cout << gcd(12, 21);
cout << lcm(12, 21);
}
快速幂
复杂度:
求
已知以下等式:
那么
a^b =
(\frac{a \times b}{c}) \% p = (a \times b \times \frac{1}{c}) \% p = (a \times b \times inv(c)) \%p
\varphi(n) = \prod{i=1}^r p_i^{k_i-1} = \prod{p|n}p^{ \alphap-1} = n \prod{p|n}(1- \frac{1}{p})
a^{\varphi(b)} \equiv 1 \mod b
$$
当b为素数就是费马小定理。