数论

 

  • 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 }
EXGCD

      求解线性同余方程

      定理:对于方程a * x + b * y = c, 该方程等价于a * x ≡ c (mod b)

                    有整数解的充分必要条件是 c % gcd(a, b) = 0

      如是,我们可以用exgcd来求出方程的一组特解

      exgcd => a * x+ b * y= gcd(a, b)  => a * c / gcd(a, b) * x0 + b * c / gcd(a, b) * y= c

      推广到所有解

      x = x+ 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])
 
      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 }
China

以上为b[i]两两互质做法

通法:扩展中国剩余定理

 假设我们这里有两个方程:
x=a1x1+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 }
exChina

 

  • 逆元(也在等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
2-100欧拉函数表

 

  • 快速幂
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 }
矩阵快速幂

 

相关题目:

P1045 麦森数

P3811 【模板】乘法逆元(说实话这个到现在也没完全会……)
posted @ 2018-06-16 09:07  hjmmm  阅读(184)  评论(0编辑  收藏  举报