前言 
本文只要写一些数论以及它的trick
最基础的部分 
唯一分解定理 
x = Π p i k i x=\Pi{p_i^{k_i}} x = Π p i k i   
公约数 
欧几里得求法 gcd  ( a , b ) = gcd  ( b , a   m o d   b ) \gcd(a,b)=\gcd(b,a\bmod b) g cd( a , b ) = g cd( b , a mod b ) 
辗转相除法  gcd  ( a , b ) = gcd  ( a − b , b ) \gcd(a,b)=\gcd(a-b,b) g cd( a , b ) = g cd( a − b , b ) 0 0 0 a a a 
唯一分解定理 gcd  ( a , b ) = Π p i min  ( k 1 i , k 2 i ) \gcd(a,b)=\Pi{p_i^{\min(k1_i,k2_i)}} g cd( a , b ) = Π p i m i n ( k 1 i  , k 2 i  )  
exgcd 
当我们想要a x + b y = k ∗ gcd  ( a , b ) , k ∈ Z , K ≠ 0 ax+by=k*\gcd(a,b),k\in Z , K \neq 0 a x + b y = k ∗ g cd( a , b ) , k ∈ Z , K  = 0 
假设我们现在求出了d = gcd  ( a , b ) d=\gcd(a,b) d = g cd( a , b ) 
那么
a x + b y = g c d ( a , b ) a d x + b d y = 1 ax+by=gcd(a,b) \\
\frac{a}{d}x+\frac{b}{d}y=1
 a x + b y = g c d ( a , b ) d a  x + d b  y = 1 
显然这个时候d ∣ a , d ∣ b d|a,d|b d ∣ a , d ∣ b 
a 0 x + b 0 y = 1 a 0 = q 1 b + r 1 b 0 = q 2 r 1 + r 2 r 1 = q 3 r 2 + r 3 a_0x+b_0y=1 \\
a_0=q_1b+r_1 \\
b_0=q_2r_1+r_2\\
r_1=q_3r_2+r_3\\
 a 0  x + b 0  y = 1 a 0  = q 1  b + r 1  b 0  = q 2  r 1  + r 2  r 1  = q 3  r 2  + r 3  
这时候根据 gcd ,我们可以求出更多的r r r 
这个时候我们可以用 gcd 求出更多的 r 然后找到 r1 ,最后就可以找到一组特解
( a 0 , b 0 ) (a_0,b_0) ( a 0  , b 0  ) 
那么很自然就会想出 exgcd
a x + b y = g c d ( a , b ) = g c d ( b , a % b ) = b x + ( a % b ) y ax+by=gcd(a,b)=gcd(b,a\%b)=bx+(a\%b)y a x + b y = g c d ( a , b ) = g c d ( b , a % b ) = b x + ( a % b ) y 
b x + ( a % b ) y = b x + ( a − ⌊ a b ⌋ ) y = a y + b x − b ⌊ a b ⌋ y = a y + b ( x − ⌊ a b ⌋ y ) bx+(a\%b)y=bx+(a-\lfloor\frac{a}{b}\rfloor)y=ay+bx-b\lfloor\frac{a}{b}\rfloor y\\=ay+b(x-\lfloor\frac{a}{b}\rfloor y) b x + ( a % b ) y = b x + ( a − ⌊ b a  ⌋) y = a y + b x − b ⌊ b a  ⌋ y = a y + b ( x − ⌊ b a  ⌋ y ) 
但是我们首先要求到 gcd 才能接 x,因此代码就要先注意一下
1 2 3 4 5 6 7 8 int  exgcd (int  a,int  b,int  &x,int  &y) 	if (b==0 ) {x=1 ;y=0 ; return  a;} 	int  t=exgcd (b,a%b,x,y),tmp=x; 	x=y; 	y=tmp-(a/b)*y; 	return  t; } 
裴蜀定理 
a x + b y = gcd  ( a , b ) , d = gcd  ( a , b ) a d x + b d y = 1 ax+by=\gcd(a,b),d=\gcd(a,b)
\\
\frac{a}{d}x+\frac{b}{d}y=1
 a x + b y = g cd( a , b ) , d = g cd( a , b ) d a  x + d b  y = 1 
如果我们把 a , b a,b a , b d d d e = a d , f = b d e=\frac{a}{d},f=\frac{b}{d} e = d a  , f = d b  
此时退化成 exgcd \text{exgcd} exgcd 
a x + b y = gcd  ( a , b ) a x + b y = gcd  ( b , a % b ) b x + a % b = gcd  ( b , a % b ) b x + ( a − b ⌊ a b ⌋ ) y = gcd  ( b , a % b ) b x + a y − b ⌊ a b ⌋ y = gcd  ( b , a % b ) a y + b ( x − ⌊ a b ⌋ y ) = gcd  ( b , a % b ) a y + b ( x − ⌊ a b ⌋ y ) = gcd  ( a , b ) ax+by=\gcd(a,b)
\\
ax+by=\gcd(b,a\%b)
\\
bx+a\%b=\gcd(b,a\%b)
\\
bx+(a-b\lfloor\frac{a}{b}\rfloor)y=\gcd(b,a\%b)
\\
bx+ay-b\lfloor\frac{a}{b}\rfloor y=\gcd(b,a\%b)
\\
ay+b(x-\lfloor\frac{a}{b}\rfloor y)=\gcd(b,a\%b)
\\
ay+b(x-\lfloor\frac{a}{b}\rfloor y)=\gcd(a,b)
 a x + b y = g cd( a , b ) a x + b y = g cd( b , a % b ) b x + a % b = g cd( b , a % b ) b x + ( a − b ⌊ b a  ⌋) y = g cd( b , a % b ) b x + a y − b ⌊ b a  ⌋ y = g cd( b , a % b ) a y + b ( x − ⌊ b a  ⌋ y ) = g cd( b , a % b ) a y + b ( x − ⌊ b a  ⌋ y ) = g cd( a , b ) 
1 2 3 4 5 6 7 8 int  exgcd (int  a,int  b,int  &x,int  &y) 	if (b==0 ) {x=1 ;y=0 ; return  a;} 	int  t=exgcd (b,a%b,x,y),tmp=x; 	x=y; 	y=tmp-(a/b)*y; 	return  t; } 
素数 
很基础的性质 
唯一分解,哈希,φ ( p ) = p − 1 \varphi(p)=p-1 φ ( p ) = p − 1 
素数密度 x ln  ( x ) \frac{x}{\ln(x)} l n ( x ) x  
判定 
由于是基础部分,只介绍三个:(不知道叫啥名字),埃筛,欧拉筛(线性筛?)
1 2 3 4 5 bool  is_prime (int  x)     for (int  i=2 ;i*i<=x;i++) if (x%i==0 ) return  1 ;     return  0 ; } 
埃筛 
1 2 3 4 5 6 7 8 9 10 11 int  is_notprime[maxn],p[maxn],cnt;void  getprime (int  x)     for (int  i=2 ;i<=x;i++)     {         if (is_notprime[i]) continue ;         for (int  j=2 ;j*i<=x;j++) is_notprime[i*j]=1 ;     }     for (int  i=2 ;i<=x;i++) if (!is_notprime[i]) p[++cnt]=i; } 
这东西的复杂度好像是 O ( n log  log  n ) O(n\log\log n) O ( n log  log  n ) 
线性筛 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int  is_notprime[maxn],p[maxn],cnt;void  getprime (int  x)     for (int  i=2 ;i<=x;i++)     {         if (!is_notprime[i]) p[++cnt]=i;         for (int  j=1 ;j<=cnt&&i*p[j]<=x;j++)          {             is_notprime[i*p[j]]=1 ;             if (i%p[j]==0 ) break ;         }     } } 
很显然的是,i ∗ p [ j ] i*p[j] i ∗ p [ j ] 1 1 1 p [ j ] p[j] p [ j ] i i i 
每个数字的最小质因子只有一个,所以是线性的。
逆元 
在模 p p p x x x x p − 1 ( m o d p ) x^{p-1} \pmod p x p − 1 ( mod p ) 
那如果 p p p 
$a \times  x \equiv 1\pmod p $
a x + p y = 1 ax+py=1 a x + p y = 1 exgcd \text{exgcd} exgcd 
中国剩余定理 
{ x ≡ 1 ( m o d   3 ) x ≡ 1 ( m o d   5 ) x ≡ 2 ( m o d   7 ) \begin{cases}x\equiv 1(mod~3)\\x\equiv 1(mod~5) \\x\equiv 2(mod~7)\end{cases} ⎩ ⎨ ⎧  x ≡ 1 ( m o d   3 ) x ≡ 1 ( m o d   5 ) x ≡ 2 ( m o d   7 )  
这个时候先得到
{ x ≡ 1 ( m o d   3 ) x ≡ 1 ( m o d   5 ) x ≡ 1 ( m o d   7 ) \begin{cases}x \equiv 1(mod~3)\\x\equiv 1(mod~5) \\x\equiv 1(mod~7)\end{cases} ⎩ ⎨ ⎧  x ≡ 1 ( m o d   3 ) x ≡ 1 ( m o d   5 ) x ≡ 1 ( m o d   7 )  
考虑特解
{ x ≡ 1 ( m o d   3 ) x ≡ 0 ( m o d   5 ) x ≡ 0 ( m o d   7 ) \begin{cases}x \equiv 1(mod~3)\\x\equiv 0(mod~5) \\x\equiv 0(mod~7)\end{cases} ⎩ ⎨ ⎧  x ≡ 1 ( m o d   3 ) x ≡ 0 ( m o d   5 ) x ≡ 0 ( m o d   7 )  
此时显然可以表示为
令
s = 3 , t = 5 ∗ 7 s=3,t=5*7 s = 3 , t = 5 ∗ 7 
M = 3 ∗ 5 ∗ 7 M=3*5*7 M = 3 ∗ 5 ∗ 7 
x = 1 + s a , x = 0 + t b x=1+sa,x=0+tb x = 1 + s a , x = 0 + t b 
1 + s a = t b , t b − s a = 1 1+sa=tb,tb-sa=1 1 + s a = t b , t b − s a = 1 
显然也可以写成
t b + s a = 1 tb+sa=1 t b + s a = 1 
那就可以通过解这个方程得到 s ,然后a n s + = s ∗ ( M / s ) ∗ 1 ans+=s*(M/s)*1 an s + = s ∗ ( M / s ) ∗ 1 
然后记得给 ans 取模,并且上面这种解法对任意互质的p 1 , p 2 , p 3 . . . p n p_1,p_2,p_3...p_n p 1  , p 2  , p 3  ... p n  
扩展中国剩余定理 
当p不互质的时候,显然存在一组g c d ( a , b ) ≠ 1 gcd(a,b)\neq1 g c d ( a , b )  = 1 
但是我们可以一直合并,让他最终变成一个同余方程,或者用对每组方程找到p作为lcm来处理,不过比上面难多了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <iostream>  #include <cmath>  #include <cstdio>  #include <cstring>  #include <queue>  #include <stack>  #include <vector>  #include <set>  #include <map>  #include <algorithm>  #define  int long long using  namespace  std;const  int  maxn=100100 ;int  b[maxn],p[maxn];int  n,m;int  x,y;int  exgcd (int  a,int  b,int  &x,int  &y) 	if (b==0 ) {x=1 ;y=0 ;  return  a;} 	int  t=exgcd (b,a%b,x,y),tmp=x; 	x=y; 	y=tmp-(a/b)*y; 	return  t; } inline  int  mul (int  x,int  y,int  modp) 	int  ans=0 ; 	while (y) 	{ 		if (y&1 ) ans=(ans+x)%modp; 		x=(x+x)%modp; 		y>>=1 ;  	} 	return  ans; } inline  int  excrt () 	int  i,j; 	int  ans=p[1 ]; 	int  nowtot=b[1 ]; 	int  lcm=1 ; 	for (i=2 ;i<=n;i++) 	{ 		int  tb,tp,tc; 		tb=nowtot; tp=b[i]; 		tc=(p[i]-ans%tp+tp)%tp; 		int  gd=exgcd (tb,tp,x,y); 		tc/=gd; 		x=mul (x,tc,tp/gd); 		ans+=x*nowtot; 		nowtot*=(tp/gd); 		ans=((ans%nowtot)+nowtot)%nowtot; 	} 	return  (ans%nowtot+nowtot)%nowtot; } signed  main () 	ios::sync_with_stdio (false ); 	register  int  i,j; 	cin>>n; 	for (i=1 ;i<=n;i++) cin>>b[i]>>p[i]; 	cout<<excrt ()<<endl; } 
Lucas 
在模一个质数 p p p C n m ( m o d p ) C^{m}_{n} \pmod p C n m  ( mod p ) 
对质数p p p 
C n m ≡ C n % p m % p ∗ C n / p m / p ( m o d   p ) C_n^m\equiv C_{n\%p}^{m\%p}*C_{n/p}^{m/p}(mod ~p) C n m  ≡ C n % p m % p  ∗ C n / p m / p  ( m o d   p ) 
但是为了方便递归理解,也有写成
L u c a s n m ≡ L u c a s n % p m % p ∗ C n / p m / p ( m o d   p ) Lucas_n^m\equiv Lucas_{n\%p}^{m\%p}*C_{n/p}^{m/p}(mod ~p) Lu c a s n m  ≡ Lu c a s n % p m % p  ∗ C n / p m / p  ( m o d   p ) 
显然这是个简单到不能再简单的结论,所以我们考虑证明
设C a b C_a^b C a b  p p p a , b a,b a , b 
a = a 0 + a 1 p + a 2 p 2 + . . . . . + a n p n a=a_0+a_1p+a_2p^2+.....+a_np^n a = a 0  + a 1  p + a 2  p 2 + ..... + a n  p n 
b = b 0 + b 1 p + b 2 p 2 + . . . . . + b n p n b=b_0+b_1p+b_2p^2+.....+b_np^n b = b 0  + b 1  p + b 2  p 2 + ..... + b n  p n 
现在我们求一下( 1 + x ) p (1+x)^p ( 1 + x ) p 
其实不用求,显而易见[ 1 , p − 1 ] [1,p-1] [ 1 , p − 1 ] 
( 1 + x ) p ≡ 1 + x p ( m o d   p ) (1+x)^p\equiv1+x^p (mod~p) ( 1 + x ) p ≡ 1 + x p ( m o d   p ) 
这东西有啥用?
回头来看命题
C n m ≡ C n % p m % p ∗ C n / p m / p ( m o d   p ) C_n^m\equiv C_{n\%p}^{m\%p}*C_{n/p}^{m/p}(mod ~p) C n m  ≡ C n % p m % p  ∗ C n / p m / p  ( m o d   p ) 
换成数学上的东西
C a b ≡ C a 0 b 0 ∗ C a 1 b 1 ∗ . . . ∗ C a n b n ( m o d   p ) C_a^b \equiv C_{a_0}^{b_0}*C_{a_1}^{b_1}*...*C_{a_n}^{b_n}(mod ~p)
 C a b  ≡ C a 0  b 0   ∗ C a 1  b 1   ∗ ... ∗ C a n  b n   ( m o d   p ) 
另外可以发现( 1 + x ) a (1+x)^a ( 1 + x ) a 
( 1 + x ) a = ( 1 + x ) a 0 ∗ ( 1 + x ) a 1 p ∗ ( 1 + x ) a 2 p 2 ∗ . . . ∗ ( ( 1 + x ) a n p n ) ( 1 + x ) a ≡ ( 1 + x ) a 0 ∗ ( 1 + x p ) a 1 ∗ ( 1 + x p 2 ) a 2 ∗ . . . ∗ ( 1 + x p n ) a n ( m o d   p ) (1+x)^a=(1+x)^{a_0}*(1+x)^{a_{1}p}*(1+x)^{a_{2} p_2}*...*((1+x)^{a_{n}p_n})\\
(1+x)^a\equiv(1+x)^{a_0}*(1+x^p)^{a_1}*(1+x^{p^2})^{a_2}*...*(1+x{p^n})^{a_n}(mod~p)
 ( 1 + x ) a = ( 1 + x ) a 0  ∗ ( 1 + x ) a 1  p ∗ ( 1 + x ) a 2  p 2  ∗ ... ∗ (( 1 + x ) a n  p n  ) ( 1 + x ) a ≡ ( 1 + x ) a 0  ∗ ( 1 + x p ) a 1  ∗ ( 1 + x p 2 ) a 2  ∗ ... ∗ ( 1 + x p n ) a n  ( m o d   p ) 
根据二项式定理,C a b C_a^b C a b  x b x^b x b 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <iostream>  #include <cstdio>  #include <cmath>  #include <cstring>  #include <queue>  #include <stack>  #include <vector>  #include <set>  #include <map>  #include <algorithm>  #define  int long long using  namespace  std;int  n,m,p;int  a[200200 ];int  qpow (int  x, int  y) 	int  ans=1 ; 	x%=p; 	while (y) 	{ 		if (y&1 ) ans=(ans*x)%p; 		x=(x*x)%p;  		y>>=1 ; 	} 	return  ans; } int  c (int  x,int  y) 	if (x<y) return  0 ; 	return  ((a[x]*(qpow (a[y],p-2 ))%p)*qpow (a[x-y],p-2 ))%p; } int  getlucas (int  x,int  y) 	if (y==0 ) return  1 ; 	return  (c (x%p,y%p)*getlucas (x/p,y/p))%p; } signed  main () 	int  t; 	register  int  i,j; 	cin>>t; 	a[0 ]=1 ; 	while (t--) 	{ 		cin>>n>>m>>p; 		for (i=1 ;i<=p;i++) a[i]=(a[i-1 ]*i)%p; 		cout<<getlucas (n+m,n)<<endl; 	}  }  
扩展卢卡斯 
先给p分解质因数,然后用一个中国剩余定理的方程组合并即可。
但是m ! ( n − m ) ! m!(n-m)! m ! ( n − m )! p k p^k p k n ! n! n ! % p \%p % p 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include <iostream>  #include <cmath>  #include <cstdio>  #include <cstring>  #include <queue>  #include <stack>  #include <vector>  #include <set>  #include <map>  #include <algorithm>  #define  int long long using  namespace  std;int  n,m,p;int  x,y;int  exgcd (int  a,int  b,int  &x,int  &y) 	if (b==0 ) {x=1 ; y=0 ;return  a;} 	int  tmp=exgcd (b,a%b,x,y),t=x; 	x=y; 	y=t-a/b*y; 	return  tmp; } inline  int  getinv (int  a,int  p) 	exgcd (a,p,x,y); 	return  ((x%p)+p)%p; } int  ksm (int  x,int  y,int  modp) 	int  ans=1 ; 	while (y) 	{ 		if (y&1 ) ans=(ans*x)%modp; 		x=(x*x)%modp; 		y>>=1 ; 	} 	return  ans; } int  f (int  x,int  pi,int  pk) 	if (x==0 ) return  1 ; 	int  p1=1 ; 	int  i,j; 	for (i=1 ;i<=pk;i++) if (i%pi) p1*=i,p1%=pk; 	p1=ksm (p1,x/pk,pk); 	for (i=1 ;i<=x%pk;i++) if (i%pi) p1*=i,p1%=pk;  	return  (f (x/pi,pi,pk)*p1)%pk; } int  getk (int  x,int  p) 	int  ans=0 ; 	while (x) ans+=x/p,x/=p; 	return  ans;  } inline  int  c (int  n,int  m,int  pi,int  pk) 	int  ta,tb,tc; 	ta=f (n,pi,pk); 	tb=f (m,pi,pk); 	tc=f (n-m,pi,pk); 	int  k=getk (n,pi); 	k-=getk (m,pi); 	k-=getk (n-m,pi); 	int  ans=((ta*getinv (tb,pk))%pk)*getinv (tc,pk); 	ans=(ans%pk)*ksm (pi,k,pk); 	ans%=pk; 	return  ans; } inline  int  crt (int  a,int  b) 	return  getinv (p/b,b)%p*(p/b)%p*(a)%p; } inline  int  exlucas (int  n,int  m) 	int  i,tmp=p; 	int  ans=0 ,pk=1 ; 	int  len=sqrt (p)+5 ; 	for (i=2 ;i<=len;i++) 	{ 		if (tmp%i!=0 ) continue ; 		pk=1 ; 		while (tmp%i==0 ) pk*=i,tmp/=i; 		ans=(ans+crt (c (n,m,i,pk),pk))%p;  	} 	if (tmp!=1 ) ans=(ans+crt (c (n,m,tmp,tmp),tmp))%p;  	return  ((ans%p)+p)%p; } signed  main () 	ios::sync_with_stdio (false ); 	cin>>n>>m>>p; 	cout<<exlucas (n,m)<<endl;  } 
1.复数
BSGS 
带步小步算法
给定一个质数 pp ,以及一个整数 bb ,一个整数 nn ,现在要求你计算一个最小的 l l l b l ≡ n ( m o d p ) b^l \equiv n \pmod p b l ≡ n ( mod p ) 
设l = k ∗ a − c l=k*a-c l = k ∗ a − c 
b k ∗ a − c ≡ n ( m o d p ) b^{k*a-c}\equiv n \pmod p b k ∗ a − c ≡ n ( mod p ) 
b k ∗ a ≡ n ∗ b c ( m o d p ) b^{k*a}\equiv n*b^c \pmod p b k ∗ a ≡ n ∗ b c ( mod p ) 
现在我们需要枚举k和c,所以要找到一个最好的c c c 
用分块思想想一想啊,显然a = p a=\sqrt{p} a = p  
而且可以保证[ 0 , p − 1 ] [0,p-1] [ 0 , p − 1 ] 
所以找符合条件的k ∗ p k*\sqrt{p} k ∗ p  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <iostream>  #include <cmath>  #include <cstdio>  #include <cstring>  #include <queue>  #include <stack>  #include <vector>  #include <set>  #include <map>  #include <algorithm>  #define  int long long using  namespace  std;const  int  max=1001000 ;map < int  , int  > mp; int  p,b,n,m; int  qpow (int  x,int  y) 	int  ans=1 ; 	while (y) 	{ 		if (y&1 ) ans=(ans*x)%p; 		x=(x*x)%p; 		y>>=1 ; 	} 	return  ans; } signed  main () 	ios::sync_with_stdio (false ); 	register  int  i,j; 	cin>>p>>b>>n; 	int  phi=p; 	m=ceil (sqrt (phi)); 	j=n; 	for (i=0 ;i<=m;i++) 	{ 		mp[j]=i; 		j=(j*b)%p; 	}  	int  jmp=qpow (b,m); 	j=jmp; 	for (i=1 ;i<=m;i++) 	{ 		if (mp.count (j)) {cout<<i*m-mp[j]<<endl; return  0 ;} 		j=(j*jmp)%p; 	} 	cout<<"no solution" <<endl; 	return  0 ; } 
欧拉定理 
欧拉函数 
ϕ ( x ) \phi(x) ϕ ( x ) φ ( x ) \varphi(x) φ ( x ) 1 → x 1\to x 1 → x x x x 
显然ϕ ( p ) = p − 1 , p \phi(p)=p-1,p ϕ ( p ) = p − 1 , p 
从这里我们可以推导出
ϕ ( p e ) = ( p − 1 ) ∗ p e − 1 \phi(p^e)=(p-1)*p^{e-1} ϕ ( p e ) = ( p − 1 ) ∗ p e − 1 
根据唯一分解定理,有
P = k 1 e 1 ∗ p 2 e 2 ∗ . . . ∗ p n e n ϕ ( P ) = ϕ ( p 1 e 1 ) ∗ ϕ ( p 2 e 2 ) ∗ . . . ∗ ϕ ( p n e n ) = Π i = 1 n ( p i − 1 ) ∗ ( p i e i − 1 ) = Π i = 1 n ( 1 − 1 p i ) ∗ ( p i e i ) = n ∗ Π i = 1 n ( 1 − 1 p i ) \begin{align}
P&=k_1^{e_1}*p_2^{e_2}*...*p_n^{e_n}\\
 \phi(P)&=\phi(p_1^{e_1})*\phi(p_2^{e_2})*...*\phi(p_n^{e_n})\\
   &= \Pi_{i=1}^{n} (p_i-1)*(p_i^{e_i-1}) \\
  &= \Pi_{i=1}^{n} (1-\frac{1}{p_i})*(p_i^{e_i}) \\
  &= n*\Pi_{i=1}^{n} (1-\frac{1}{p_i})
\end{align}
 P ϕ ( P )  = k 1 e 1   ∗ p 2 e 2   ∗ ... ∗ p n e n   = ϕ ( p 1 e 1   ) ∗ ϕ ( p 2 e 2   ) ∗ ... ∗ ϕ ( p n e n   ) = Π i = 1 n  ( p i  − 1 ) ∗ ( p i e i  − 1  ) = Π i = 1 n  ( 1 − p i  1  ) ∗ ( p i e i   ) = n ∗ Π i = 1 n  ( 1 − p i  1  )   
我们就可以用这种方式求出ϕ ( n ) \phi(n) ϕ ( n ) 
1 2 3 4 5 6 7 8 9 10 void  phi_table (int  n) 	phi[1 ]=1 ;	 	for (int  i=2 ;i<=n;i++) if (!phi[i]) 	for (int  j=i;j<=n;j+=i) 	{	 		if (!phi[j])phi[j]=j; 		phi[j]=phi[j]/i*(i-1 ); 	} } 
对于单个n,还有一个O ( N ) O(\sqrt{N}) O ( N  ) 
1 2 3 4 5 6 7 8 9 10 signed  main () 	ios::sync_with_stdio (false ); 	register  int  i; 	cin>>m; 	phi=m; 	for (i=2 ;i*i<=m;i++)  	if (tmp%i==0 ){phi-=phi/i; while (tmp%i==0 ) tmp/=i;} 	if (tmp!=1 ) phi-=phi/tmp; } 
欧拉定理 
a ϕ ( m ) ≡ 1 (   m o d   m ) , a ⊥ m a^{\phi(m)}\equiv1 (~mod~m),a\perp m a ϕ ( m ) ≡ 1 (   m o d   m ) , a ⊥ m 
证明:证明这个数有ϕ \phi ϕ a p − 1 a^{p-1} a p − 1 p p p a a a 
扩展欧拉定理 
先咕一下证明(两年了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <iostream>  #include <cmath>  #include <cstdio>  #include <cstring>  #include <queue>  #include <stack>  #include <vector>  #include <set>  #include <map>  #include <algorithm>  #define  int long long using  namespace  std;int  a,b,m,phi,tmp,bj;inline  void  qread (int  &x) 	x=0 ; 	static  char  c=getchar (); 	while (!isdigit (c)) c=getchar (); 	while (isdigit (c)) {x=x*10 +c-'0' ; if (x>=phi) x%=phi,bj=1 ; c=getchar ();} 	return  ; } inline  int  ksm (int  x,int  y,int  modp) 	int  ans=1 ; 	while (y) 	{ 		if (y&1 ) ans=(ans*x)%modp; 		x=(x*x)%modp; 		y>>=1 ; 	} 	return  ans; } signed  main () 	 	register  int  i,j; 	cin>>a>>m; 	phi=m; tmp=m; 	for (i=2 ;i*i<=m;i++)  	if (tmp%i==0 ){phi-=phi/i; while (tmp%i==0 ) tmp/=i;} 	if (tmp!=1 ) phi-=phi/tmp; 	qread (b); 	cout<<ksm (a,bj?b+phi:b,m); }