数论
- GCD 最大公约数
--辗转相除法
1 inline int gcd(int a, int b){ 2 return b ? gcd(b, a % b) : a; 3 }
LCM 最小公倍数
lcm(a, b) = a * b / gcd(a, b);
- EXGCD 扩展欧几里得算法
已知(a, b), 求解一组(p, q), 使得p * a + q * b = gcd(a, b)
推导过程:
gcd(a, b) = gcd(b, a % b)
p * a + q * b
= p * b + q * (a % b)
= p * b + q * (a - a / b * b) // 此处使用了int的下取整
= q * a + (p - a / b * q) * b
边界 : 当 b == 0 时,p = 1, q = 0
1 inline void exgcd(int a, int b, int &x, int &y){ 2 if(!b) {x = 1; y = 0; return ;} 3 exgcd(b, b % a, y, x); 4 y -= a / b * x; 5 }
求解线性同余方程
定理:对于方程a * x + b * y = c, 该方程等价于a * x ≡ c (mod b)
有整数解的充分必要条件是 c % gcd(a, b) = 0
如是,我们可以用exgcd来求出方程的一组特解
exgcd => a * x0 + b * y0 = gcd(a, b) => a * c / gcd(a, b) * x0 + b * c / gcd(a, b) * y0 = c
推广到所有解
x = x0 + b / gcd(a, b) * t;
y = y0 + a / gcd(a, b) * t;
- 中国剩余定理(还在等待W小姐解答
求解模线性方程组
a ≡ b[1] (mod w[1])
a ≡ b[2] (mod w[2])
China
exChina
a ≡ b[3] (mod w[3])
…………
a ≡ b[k] (mod w[k])
1 inline void exgcd(int a, int b, int &x, int &y){ 2 if(!b) {x = 1; y = 0; return ;} 3 exgcd(b, b % a, y, x); 4 y -= a / b * x; 5 } 6 int China(int w[], int b[], int k){ 7 int x, y, a = 0, m, n = 1; 8 for(int i = 1; i <= k; i++) n *= w[i]; 9 for(int i = 1; i <= k; i++){ 10 m = n / w[i]; 11 exgcd(w[i], m, x, y); 12 a = (a + y * m * b[i]) % n; 13 } 14 return (a + n) % n; 15 }
以上为b[i]两两互质做法
通法:扩展中国剩余定理
假设我们这里有两个方程:
x=a1∗x1+b1
x=a1∗x1+b1
a1
,a2是模数,b1
,b2
是余数。
那么我们可以合并这两个方程:
a1 ∗ x1 + b1 = a2 ∗ x2 + b2
,
变形得:a1 ∗ x1 + a2 ∗ x2 = b2 − b1
由扩展欧几里得得最小正整数解x1
令k = (a1 ∗ x1 + b1)
得到新方程:
x ≡ k (mod lcm(a1, a2))
一直合并下去就okk
1 代码来自 : https://blog.csdn.net/litble/article/details/75807726 2 LL work(){ 3 LL M=m[1],A=a[1],t,d,x,y;int i; 4 //a[i]是余数 m[i]是模数 5 for(i=2;i<=n;i++){ 6 d=exgcd(M,m[i],x,y); //解方程 7 if((a[i]-A)%d) return -1; //无解 8 x*=(a[i]-A)/d; // 9 t=m[i]/d; // 10 x=(x%t+t)%t; //将ax + by = gcd(a, b)转为方程(最小正整数)解 11 A=M*x+A; //合并过程 12 M=M/d*m[i]; // 13 A%=M; //取模 14 } 15 A=(A%M+M)%M; //最小正整数 16 return A; 17 }
- 逆元(也在等W小姐……
- 线性筛质数
1 void pri_table(int n){ 2 for(int i = 1; i <= n; i++) not_pri[i] = 0; 3 for(int i = 2; i <= n; i++){ 4 if(!not_pri[i]) prime[++psize] = i; 5 for(int j = 1; j <= psize; j++){ 6 if(i * prime[j] > n) break; 7 not_pri[i * prime[j]] = 1; 8 if(i % prime[j] == 0) break; 9 } 10 } 11 }
- 欧拉函数
线性筛法其实是质数线性筛法的推广
1 bool not_pri[N]; 2 int prime[N], psize, phi[N]; 3 void pri_table(int n){ 4 for(int i = 1; i <= n; i++) not_pri[i] = 0; 5 for(int i = 2; i <= n; i++){ 6 if(!not_pri[i]){ 7 prime[++psize] = i; 8 phi[i] = i - 1; 9 } 10 for(int j = 1; j <= psize; j++){ 11 if(i * prime[j] > n) break; 12 not_pri[i * prime[j]] = 1; 13 if(i % prime[j] == 0){ 14 phi[i * prime[j]] = phi[i] * prime[j]; 15 break; 16 } 17 else phi[i * prime[j]] = phi[i] * (prime[j] - 1); 18 } 19 } 20 }
用来检查的函数表……
n φ(n) 2 1 3 2 4 2 5 4 6 2 7 6 8 4 9 6 10 4 11 10 12 4 13 12 14 6 15 8 16 8 17 16 18 6 19 18 20 8 21 12 22 10 23 22 24 8 25 20 26 12 27 18 28 12 29 28 30 8 31 30 32 16 33 20 34 16 35 24 36 12 37 36 38 18 39 24 40 16 41 40 42 12 43 42 44 20 45 24 46 22 47 46 48 16 49 42 50 20 51 32 52 24 53 52 54 18 55 40 56 24 57 36 58 28 59 58 60 16 61 60 62 30 63 36 64 32 65 48 66 20 67 66 68 32 69 44 70 24 71 70 72 24 73 72 74 36 75 40 76 36 77 60 78 24 79 78 80 32 81 54 82 40 83 82 84 24 85 64 86 42 87 56 88 40 89 88 90 24 91 72 92 44 93 60 94 46 95 72 96 32 97 96 98 42 99 60 100 40
- 快速幂
1 int ans = 1; 2 while(p > 0){ 3 if(p & 1 == 1) { 4 ans = (ans * b) % k; 5 } 6 b = (b * b) % k; 7 p = p >> 1; 8 }
↑ 求bp % k
- 矩阵快速幂
1 void matrix_pow(long long y){ 2 int i, j, k; 3 memset(ans, 0, sizeof(ans)); 4 for(i = 1; i <= n; i++) 5 ans[i][i] = 1; 6 //设置初始矩阵 只有主对角线(左上到右下)是1 其余为0 7 while(y > 0){ 8 if(y & 1){ 9 memset(temp, 0, sizeof(temp)); 10 for(i = 1; i <= n; i++) 11 for(j = 1; j <= n; j++) 12 for(k = 1; k <= n; k++) 13 temp[i][j] = (temp[i][j] + ans[i][k] * mat[k][j]) % P; 14 15 for(i = 1; i <= n; i++) 16 for(j = 1; j <= n; j++) 17 ans[i][j] = temp[i][j]; 18 //矩阵乘法 相当于(ans * mat)% P 19 } 20 memset(temp, 0, sizeof(temp)); 21 int i, j, k; 22 for(i = 1; i <= n; i++) 23 for(j = 1; j <= n; j++) 24 for(k = 1; k <= n; k++) 25 temp[i][j] = (temp[i][j] + mat[i][k] * mat[k][j]) % P; 26 for(i = 1; i <= n; i++) 27 for(j = 1; j <= n; j++) 28 mat[i][j] = temp[i][j]; 29 //矩阵乘法 相当于(mat * mat) % P 30 y >>= 1; 31 } 32 }
相关题目:
P3811 【模板】乘法逆元(说实话这个到现在也没完全会……)
P3390 【模板】矩阵快速幂
P1226 取余运算||快速幂