boolis_prime(int x){ if (x < 2) returnfalse; for (int i = 2; i <= x / i; i++) if (x % i == 0) returnfalse; returntrue; }
试除法分解质因数
1 2 3 4 5 6 7 8 9 10
voiddivide(int x){ for (int i = 2; i <= x / i; i++) if (x % i == 0) { int s = 0; while (x % i == 0) x /= i, s++; cout << i << ' ' << s << endl; } if (x > 1) cout << x << ' ' << 1 << endl; cout << endl; }
voidget_primes(int n){ for (int i = 2; i <= n; i++) { if (st[i]) continue; primes[cnt++] = i; // 筛去所有 i 的倍数 for (int j = i + i; j <= n; j += i) st[j] = true; } }
线性筛法求素数
1 2 3 4 5 6 7 8 9 10
voidget_primes(int n){ for (int i = 2; i <= n; i++) { if (!st[i]) primes[cnt++] = i; for (int p : primes) { if (p * i > n) break; st[p * i] = true; if (i % p == 0) break; } } }
试除法求所有约数
1 2 3 4 5 6 7 8 9 10
vector<int> get_divisors(int x){ vector<int> res; for (int i = 1; i <= x / i; i++) if (x % i == 0) { res.push_back(i); if (i != x / i) res.push_back(x / i); } sort(res.begin(), res.end()); return res; }
intgcd(int a, int b){ return b ? gcd(b, a % b) : a; }
求欧拉函数
1 2 3 4 5 6 7 8 9 10
intphi(int x){ int res = x; for (int i = 2; i <= x / i; i++) if (x % i == 0) { res = res / i * (i - 1); while (x % i == 0) x /= i; } if (x > 1) res = res / x * (x - 1); return res; }
int primes[N], cnt = 0; // primes[]存储所有素数,cnt为素数个数 bool st[N] = {false}; // st[x]存储x是否被筛掉 int euler[N]; // 存储每个数的欧拉函数
voidget_eulers(int n){ euler[1] = 1; for (int i = 2; i <= n; i++) { if (!st[i]) { primes[cnt++] = i; euler[i] = i - 1; } for (int j = 0; primes[j] <= n / i; j++) { int t = primes[j] * i; st[t] = true; if (i % primes[j] == 0) { euler[t] = euler[i] * primes[j]; break; } euler[t] = euler[i] * (primes[j] - 1); } } }
快速幂
1 2 3 4 5 6 7 8 9
intQuickPow(int a, int b, int m){ int ans = 1; while (b) { if (b & 1) ans = ans * a % m; a = a * a % m; b >>= 1; } return ans; }
扩展欧几里得算法
1 2 3 4 5 6 7 8 9 10 11
// 求x, y,使得ax + by = gcd(a, b) intexgcd(int a, int b, int &x, int &y){ if (b == 0) { x = 1; y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= (a / b) * x; return d; }
// a[N][N]是增广矩阵 intgauss(){ int c, r; for (c = 0, r = 0; c < n; c++) { int t = r; for (int i = r; i < n; i++) // 找到绝对值最大的行 if (fabs(a[i][c]) > fabs(a[t][c])) t = i;
if (fabs(a[t][c]) < eps) continue;
for (int i = c; i <= n; i++) swap(a[t][i], a[r][i]); // 将绝对值最大的行换到最顶端 for (int i = n; i >= c; i--) a[r][i] /= a[r][c]; // 将当前行的首位变成1 for (int i = r + 1; i < n; i++) // 用当前行将下面所有的列消成0 if (fabs(a[i][c]) > eps) for (int j = n; j >= c; j--) a[i][j] -= a[r][j] * a[i][c];
r++; }
if (r < n) { for (int i = r; i < n; i++) if (fabs(a[i][n]) > eps) return2; // 无解 return1; // 有无穷多组解 }
for (int i = n - 1; i >= 0; i--) for (int j = i + 1; j < n; j++) a[i][n] -= a[i][j] * a[j][n];
return0; // 有唯一解 }
递归法求组合数
1 2 3 4 5 6 7
// 计算 C(a,b)%p int ans[1000][1000] = {0}; intC(int a, int b, int p){ if (b == 0 || a == b) return1; if (ans[a][b] != 0) return ans[a][b]; return ans[a][b] = (C(a - 1, b) + C(a - 1, b - 1)) % p; }
通过预处理逆元的方式求组合数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
//首先预处理出所有阶乘取模的余数fact[N],以及所有阶乘取模的逆元infact[N] //如果取模的数是质数,可以用费马小定理求逆元 intQuickPow(int a, int b, int m){ // 快速幂模板 int ans = 1; while (b) { if (b & 1) ans = ans * a % m; a = a * a % m; b >>= 1; } return ans; }
// 预处理阶乘的余数和阶乘逆元的余数 fact[0] = infact[0] = 1; for (int i = 1; i < N; i++) { fact[i] = (LL)fact[i - 1] * i % mod; infact[i] = (LL)infact[i - 1] * QuickPow(i, mod - 2, mod) % mod; }
Lucas 定理
若 p 是质数,则对于任意整数 1 <= m <= n 有:
C(n, m) = C(n % p, m % p) * C(n / p, m / p) (mod p)
1 2 3 4
intlucas(int a, int b, int p){ if (a < p && b < p) returnC(a, b, p); returnC(a % p, b % p, p) * lucas(a / p, b / p, p) % p; }