[数论专题]

一:素数

 1 int prime[N],p[N],tot;
 2 void init()
 3 {
 4     for(int i=2;i<N;i++)    prime[i]=1;
 5     for(int i=2;i<N;i++)
 6     {
 7         if(prime[i]==1) p[++tot]=i;
 8         for(int j=1;j<=tot;j++)
 9         {
10             prime[i*p[j]]=0;
11             if(i%p[j]==0)   break;
12         }
13     }
14 }
View Code

二:快速幂

1 LL pow_mod(LL a, LL b, LL p){//a的b次方求余p
2     LL ret = 1;
3     while(b){
4         if(b & 1) ret = (ret * a) % p;
5         a = (a * a) % p;
6         b >>= 1;
7     }
8     return ret;
9 }
View Code

快速乘

1 LL mul(LL a, LL b, LL p){//快速乘,计算a*b%p
2     LL ret = 0;
3     while(b){
4         if(b & 1) ret = (ret + a) % p;
5         a = (a + a) % p;
6         b >>= 1;
7     }
8     return ret;
9 }
View Code

三:gcd和lcm

lcm=a/gcd*b;

1 LL gcd(LL a, LL b){
2     if(b == 0) return a;
3     else return gcd(b, a%b);
4 }
5 
6 LL gcd(LL a, LL b){
7     return b ? gcd(b, a%b) : a;
8 }
9 //两种都可以
gcd

gcd(ka, kb) = k * gcd(a, b)

lcm(ka, kb) = k * lcm(a, b)

lcm(S/a, S/b) = S/gcd(a, b)

四:扩展欧几里得算法

已知 a,b 求 一组解 x,y 满足 ax+by = gcd(a, b) 这个公式

 1  void ex_gcd(LL a, LL b, LL &d, LL &x, LL &y)
 2 {
 3     if(!b)
 4         {d = a; x = 1; y = 0;}
 5      else
 6     {
 7         ex_gcd(b, a%b, d, y, x); 
 8         y -= x*(a/b);
 9     }    
10 }
View Code

五:数论四大定理

1.威尔逊定理:

  当且仅当p为素数时:( p -1 )! ≡ -1 ( mod p )

  或者这么写( p -1 )! ≡ p-1 ( mod p )

  或者说

  若p为质数,则p能被(p-1)!+1整除

2.欧拉定理:

 
  若n,a为正整数,且n,a互质,即gcd(a,n) = 1,则
   a^φ(n) ≡ 1 (mod n)
 
   φ(n) 是欧拉函数
 
    欧拉函数是求 1到n-1 中 与n互质的数 的数目
 3.中国剩余定理

  假设整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,方程组 (S)有解

 1 #include<cstdio>
 2 typedef long long LL;
 3 const int N = 100000 + 5;
 4 void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
 5     if (!b) {d = a, x = 1, y = 0;}
 6     else{
 7         ex_gcd(b, a % b, y, x, d);
 8         y -= x * (a / b);
 9     }
10 }
11 LL inv(LL t, LL p){//如果不存在,返回-1
12     LL d, x, y;
13     ex_gcd(t, p, x, y, d);
14     return d == 1 ? (x % p + p) % p : -1;
15 }
16 LL china(int n, LL *a, LL *m){//中国剩余定理
17     LL M = 1, ret = 0;
18     for(int i = 0; i < n; i ++) M *= m[i];
19     for(int i = 0; i < n; i ++){
20         LL w = M / m[i];
21         ret = (ret + w * inv(w, m[i]) * a[i]) % M;
22     }
23     return (ret + M) % M;
24 }
25 int main(){
26     LL p[3], r[3], d, ans, MOD = 21252;
27     int cas = 0;
28     p[0] = 23; p[1] = 28; p[2] = 33;
29     while(~scanf("%I64d%I64d%I64d%I64d", &r[0], &r[1], &r[2], &d) && (~r[0] || ~r[1] || ~r[2] || ~d)){
30         ans = ((china(3, r, p) - d) % MOD + MOD) % MOD;
31         printf("Case %d: the next triple peak occurs in %I64d days.
", ++cas, ans ? ans : 21252);
32     }
33 
34 }
View Code
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long LL;
 5 typedef pair<LL, LL> PLL;
 6 PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
 7     LL x = 0, m = 1;
 8     for(int i = 0; i < n; i ++) {
 9         LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
10         if(b % d != 0)  return PLL(0, -1);//答案不存在,返回-1
11         LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
12         x = x + m*t;
13         m *= M[i]/d;
14     }
15     x = (x % m + m ) % m;
16     return PLL(x, m);//返回的x就是答案,m是最后的lcm值
17 }
不互质情况

4.费马小定理:

  假如p是质数,若p不能整除a,则 a^(p-1) ≡1(mod p),若p能整除a,则a^(p-1) ≡0(mod p)。
  或者说,若p是质数,且a,p互质,那么 a的(p-1)次方除以p的余数恒等于1。
 

六:逆元

求单个逆元:   inv[a]=pow(a,mod-2,mod);

求n个数的逆元: inv[0]=inv[1]=1;  inv[i]=(mod-mod/i)*inv[mod%i];

七:欧拉函数

 1 #include<cstdio>
 2 using namespace std;
 3 const int N = 1e6+10 ;
 4 int phi[N], prime[N];
 5 int tot;//tot计数,表示prime[N]中有多少质数
 6 void Euler(){
 7     phi[1] = 1;
 8     for(int i = 2; i < N; i ++){
 9         if(!phi[i]){
10             phi[i] = i-1;
11             prime[tot ++] = i;
12         }
13         for(int j = 0; j < tot && 1ll*i*prime[j] < N; j ++){
14             if(i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j]-1);
15             else{
16                 phi[i * prime[j] ] = phi[i] * prime[j];
17                 break;
18             }
19         }
20     }
21 }
22 
23 int main(){
24     Euler();
25 }
View Code

八:卢卡斯定理

求Cnm,用逆元为O(n)的。

但若 n m 特别大,p很小的时候。

C(n, m) % p  =  C(n / p, m / p) * C(n%p, m%p) % p

 

九:康托展开

康托的一套算法可以正好产生n!个数字

比如:

123  ->  0

132  ->  1

213  ->  2

231  ->  3

312  ->  4

321  ->  5

 1 void cantor(int s[], LL num, int k){//康托展开,把一个数字num展开成一个数组s,k是数组长度
 2     int t;
 3     bool h[k];//0到k-1,表示是否出现过
 4     memset(h, 0, sizeof(h));
 5     for(int i = 0; i < k; i ++){
 6         t = num / fac[k-i-1];
 7         num = num % fac[k-i-1];
 8         for(int j = 0, pos = 0; ; j ++, pos ++){
 9             if(h[pos]) j --;
10             if(j == t){
11                 h[pos] = true;
12                 s[i] = pos + 1;
13                 break;
14             }
15         }
16     }
17 }
18 void inv_cantor(int s[], LL &num, int k){//康托逆展开,把一个数组s换算成一个数字num
19     int cnt;
20     num = 0;
21     for(int i = 0; i < k; i ++){
22         cnt = 0;
23         for(int j = i + 1; j < k; j ++){
24             if(s[i] > s[j]) cnt ++;//判断几个数小于它
25         }
26         num += fac[k-i-1] * cnt;
27     }
28 }
View Code

hdu 1430(坑)

十:抽屉原理

原文地址:https://www.cnblogs.com/Kaike/p/12987450.html