// 质数判定
(1) 暴力
bool check(int x) {
for (int i = 2; i * i <= x; ++i) if (x % i == 0) return 0;
return 1;
}
(2)miller_rabin
bool check(LL a) {
for (int i = 0; i < 12; ++i) {
if(f[i] >= a) break;
if(Qpow(f[i], a - 1, a) != 1) return 0;
LL pp = a - 1;
while(pp % 2 == 0) {
pp /= 2; LL y = Qpow(f[i], pp, a);
if(Qmul(y, y, a) == 1 && y != 1 && y != a - 1) return 0;
}
} return 1;
}
//n的所有约数
vector <int> a;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
a.push_back(i);
if (i * i != n) a.push_back(n / i);
}
}
//分解质因数
vector <int> p, c;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
p.push_back(i);
int cnt = 0;
while (n % i == 0) ++ cnt, n /= i;
c.push_back(cnt);
}
}
if (n > 1) p.push_back(n), c.push_back(1);
//线性筛
(1)筛质数
for (int i = 2; i <= lim; ++i) {
if (!vis[i]) pri[++ cnt] = i;
for (int j = 1; j <= cnt && i * pri[j] <= lim; ++j) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
}
}
(2)筛欧拉函数
phi[1] = 1;
for (int i = 2; i <= lim; ++i) {
if (!vis[i]) pri[++ cnt] = i, phi[i] = i - 1;
for (int j = 1; j <= cnt && i * pri[j] <= lim; ++j) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) {
phi[i * pri[j]] = phi[i] * pri[j]; break;
}
phi[i * pri[j]] = phi[i] * phi[pri[j]];
}
}
(3) 筛约束约数个数
记t[i]为i的约数个数,e[i]为i的最小素因子的个数
因为是线性筛,每个数只被它最小的质因子筛到,所以
a pri[j]是i*pri[j]的最小质因子
b 如果i是pri[j]的倍数,pri[j]也是i的最小质因子
<1> i是素数,t[i] = 2, e[i] = 1
<2> i是pri[j]的倍数
t[i * pri[j]] = t[i] / (e[i] + 1) * (e[i] + 2)
e[i] = e[i] + 1
<3> i不是pri[j]的倍数
t[i * pri[j]] = t[i] * t[pri[j]]
e[i * pri[j]] = 1
for (int i = 2; i <= lim; ++i) {
if (!vis[i]) pri[++ cnt] = i, t[i] = 2, e[i] = 1;
for (int j = 1; j <= cnt && i * pri[j] <= lim; ++j) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) {
e[i * pri[j]] = e[i] + 1;
t[i * pri[j]] = t[i] / (e[i] + 1) * (e[i] + 2); break;
}
e[i * pri[j]] = 1;
t[i * pri[j]] = t[i] * t[pri[j]];
}
}
(4)筛约数和
记t[i]为i的约数和,e[i]为i的最小素因子的那一项等比数列
t[i] = (1 + p1 + p1^2 + ...)(1 + p2 + p2^2 + ....) ...(1 + pn + pn^2 + ...)
e[i] = (1 + p1 + p1^2 + ...)
因为是线性筛,每个数只被它最小的质因子筛到,所以
a pri[j]是i*pri[j]的最小质因子
b 如果i是pri[j]的倍数,pri[j]也是i的最小质因子
<1> i是素数,t[i] = i + 1, e[i] = i + 1
<2> i是pri[j]的倍数
t[i * pri[j]] = t[i] / e[i] * (e[i] * pri[j] + 1)
e[i * pri[j]] = e[i] * pri[j] + 1
<3> i不是pri[j]的倍数
t[i * pri[j]] = t[i] * (pri[j] + 1)
e[i * pri[j]] = pri[j] + 1
for (int i = 2; i <= lim; ++i) {
if(!vis[i]) pri[++ cnt] = i, e[i] = t[i] = i + 1;
for (int j = 1; j <= cnt && i * pri[j] <= lim; ++j) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0) {
t[i * pri[j]] = t[i] / e[i] * (e[i] * pri[j] + 1);
e[i * pri[j]] = e[i] * pri[j] + 1;
}
t[i * pri[j]] = t[i] * (pri[j] + 1);
e[i * pri[j]] = pri[j] + 1;
}
}
//ECGCD
void Exgcd(int a, int b, int &x, int &y) {
if (b == 0) {x = 1; y = 0; return;}
Exgcd(b, a % b, y, x);
y -= a / b * x;
}
方程 ax + by = c有解, 当且仅当 gcd(a, b) | c
d = gcd(a, b)
a /= d, b /= d, c /= d
通解: x = x * c + k * b, y = y * c - k * a
最小正整数解 x *= c, x = (x % b + b) % b
//线性同余方程
求解 ax=b(mod m)
转化为:ax + my = b
tips:求解 ax + by = c时
若 a < 0, 则 a = -a, c = -c
//线性同余方程组
x = b1 (mod a1)
x = b2 (mod a2)
b1 + a1 * x1 = b2 + a2 * x2
a1 * x1 + a2 * x2 = b2 - b1
解出最小的正整数解x'
得到新方程 x = (a1 * x' +b1) (mod lcm(a1, b2))
LL excrt() {
LL M = a[1], B = b[1], x, y;
for (int i = 2; i <= n; ++i) {
LL C = b[i] - B;
LL d = gcd(M, a[i]);
if (C % d) return -1;
exgcd(M, a[i], x, y);
x = Mul(x, C / d, a[i] / d);
B += x * M;
M = M / d * a[i];
B = (B % M + M) % M;
}
return B;
}
//欧拉函数
phi[i]表示1...i中与i互质数的个数
i = p1 ^ a1 * p2 ^ a2 *...pn ^ a
phi[i] = sum{i / pj * (pj - 1)}
//欧拉定理
当gcd(a, n) = 1时, a ^ phi[n] = 1 (mod n)
推论
<1> 若gcd(a, n) = 1, 则a ^ b = a ^ (b % phi[n]) (mod n)
<2> 若b > phi[n], 则a ^ b = a ^ (b % phi[n] + phi[n]) (mod n)
//费马小定理
<1> p是质数,gcd(a, p) = 1, 则a ^ (p - 1) = 1 (mod p)
<2> p是质数,对于任意a, a ^ p = a (mod p)
//乘法逆元
a * x = 1 (mod m)
x 为 a 在mod m意义下的逆元
求法
<1> m 为质数 pow(a, m - 2) 为逆元
<2> ax + bm = 1, exgcd求解即可
<3> 递推 inv[1] = 1, inv[i] = (p - p / i) * inv[p % i]
//组合数 C(n, m) = n! / (m! * (n - m)!)
递推 :
c[0][0] = 1;
for (int i = 1; i <= n; ++i) {
c[i][0] = c[i][i] = 1;
for (int j = 1; j <= i - 1; ++j)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
//二项式定理
(a + b) ^ n = sum {C(n, i) * a ^ i * b ^ (n - i)} (0 <= i <= n)
//卡特兰数
P(n) = C(2n, n) - C(2n, n - 1) = 1 / (n + 1) * C(2n, n)
前几项:(n从0开始)
1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786
递推:
P0 = 1
<1> Pn = sum {Pi * Pn - i + 1} (0 <= i <= n - 1)
<2> Pn+1 = 2 * (2n + 1) / (n + 2) * Pn
奇卡特兰数满足 n = 2 ^ k - 1
https://quincyqiang.cn/2017/08/24/06-%E5%8D%A1%E7%89%B9%E5%85%B0%E6%95%B0/
http://blog.miskcoo.com/2015/07/catalan-number