📕NOIP 数论笔记,素数筛法、欧几里得、扩展欧几里得、欧拉函数、欧拉定理、费马小定理、逆元、求解同余方程(中国剩余定理)
素数筛法
对于少量的判断一个 n 是不是素数,我们可以通过暴力 O ( n ) O(\sqrt{n}) O ( n ) 的复杂度解决,而当题目需要判断大量素数时便引入了筛法求素数。
朴素的筛法
遇到一个数把它的所有倍数标记掉,依次筛,没有标记的就是素数。复杂度 O ( n log n ) O(n\log n) O ( n log n )
1 2 3 4 5 6 7 8 9 void init (int n) { int up = (int )sqrt (n) + 1 ; for (int i = 2 ; i <= up; i++) for (int j = i * i; j <= n; j += i) flag[j] = true ; for (int i = 2 ; i <= n; i++) { if (!flag[i]) p[tot++] = i; } }
线性筛素数
O ( n ) O(n) O ( n ) 筛素数,每一个数只被其最小的素因子筛选到
1 2 3 4 5 6 7 8 9 10 11 12 void init (int n) { for (int i = 2 ; i <= n; i++) { if (!flag[i]) p[tot++] = i; for (int j = 0 ; j < tot; j++) { if (i * p[j] > n) break ; flag[i * p[j]] = true ; if (i % p[j] == 0 ) { break ; } } } }
欧几里得
求两数最大公约数
辗转相减
求两数 a , b a,b a , b 的最大公约数 gcd ( a , b ) \gcd(a,b) g cd( a , b ) ,假设 a > b a>b a > b ,则 gcd ( a , b ) = g c d ( a − b , b ) \gcd(a,b)=gcd(a-b,b) g cd( a , b ) = g c d ( a − b , b ) ,直到其中一个为零,另一个就是 gcd \gcd g cd 。
证明:
令 a = k 1 × g a=k_1\times g a = k 1 × g ,令 b = k 2 × g b=k_2\times g b = k 2 × g ;
假设 a , b a,b a , b 的最大公约数是 g g g 则 gcd ( k 1 , k 2 ) = 1 \gcd(k_1,k_2)=1 g cd( k 1 , k 2 ) = 1 ;
每次操作令 a = a − b a=a-b a = a − b ,a = ( k 1 − k 2 ) × g a=(k_1-k_2)\times g a = ( k 1 − k 2 ) × g ,b = k 2 × g b=k_2 \times g b = k 2 × g ;
可以证明 k 1 − k 2 k_1-k_2 k 1 − k 2 与 k 2 k_2 k 2 还是互质的(反证法),那么当其中一个 k k k 减到零,另一个 k k k 为一便是 g g g 了。
1 2 3 4 5 int gcd (int x, int y) { if (x < y) return gcd (y, x); if (y == 0 ) return x; return gcd (x - y, y); }
辗转相除
显然上面的做法复杂度太高,有许多多余的计算,当 a = 101 , b = 2 a=101,b=2 a = 1 0 1 , b = 2 时就要减好几次,显然的目的是减到 a < b a<b a < b 为止再交换 a a a 和 b b b ,那么就等同于 a m o d b a\bmod b a m o d b ,故 gcd ( a , b ) = gcd ( a m o d b , b ) \gcd(a,b)=\gcd(a\bmod b,b) g cd( a , b ) = g cd( a m o d b , b )
1 2 3 int gcd (int a, int b) { return !b ? a : gcd (b, a % b); }
扩展欧几里得
通过扩展欧几里得解决形如 a x + b y = c ax+by=c a x + b y = c 的二元一次方程,求解的存在性,特解、通解。
解的存在性
有一个显然的定理:gcd ( k 1 , k 2 ) = 1 \gcd(k_1,k_2)=1 g cd( k 1 , k 2 ) = 1 则方程 k 1 x + k 2 y = 1 k_1x+k_2y=1 k 1 x + k 2 y = 1 一定有解(上面的辗转相减告诉我们对于互质的两数 k 1 , k 2 k_1,k_2 k 1 , k 2 ,辗转相减可以减到 1 1 1 。对于上式,乘上 gcd ( a , b ) \gcd(a,b) g cd( a , b ) :
k 1 gcd ( a , b ) x + k 2 gcd ( a , b ) y = gcd ( a , b ) k_1\gcd(a,b)x+k_2\gcd(a,b)y=\gcd(a,b)
k 1 g cd( a , b ) x + k 2 g cd( a , b ) y = g cd( a , b )
a x + b y = gcd ( a , b ) ax+by=\gcd(a,b)
a x + b y = g cd( a , b )
一定有解。
那么若 c c c 是 gcd ( a , b ) \gcd(a,b) g cd( a , b ) 的倍数,即 c m o d gcd ( a , b ) = 0 c\bmod \gcd(a,b)=0 c m o d g cd( a , b ) = 0 则有解。
特解与通解
对于原方程 a x + b y = c ax+by=c a x + b y = c ,我们其实只要求出
a x + b y = gcd ( a , b ) ax+by=\gcd(a,b)
a x + b y = g cd( a , b )
的解再乘上 c g c d ( a , b ) \dfrac{c}{gcd(a,b)} g c d ( a , b ) c 就行了。我们考虑缩小规模,假设我们已经求出
( a − b ) x 1 + b y 1 = g c d ( a − b , b ) (a-b)x_1+by_1=gcd(a-b,b)
( a − b ) x 1 + b y 1 = g c d ( a − b , b )
的解 x 1 , y 1 x_1,y_1 x 1 , y 1 ,那么变化一下式子可得
a x 1 − b x 1 + b y 1 = gcd ( a , b ) ax_1-bx_1+by_1=\gcd(a,b)
a x 1 − b x 1 + b y 1 = g cd( a , b )
a x 1 + b ( y 1 − x 1 ) = gcd ( a , b ) ax_1+b(y_1-x_1)=\gcd(a,b)
a x 1 + b ( y 1 − x 1 ) = g cd( a , b )
观察一下式子,是不是 x = x 1 , y = y 1 − x 1 x=x_1,y=y_1-x_1 x = x 1 , y = y 1 − x 1 。
所以我们可以把原问题变成一个规模更小的子问题,求出子问题的解,推出当前的解,故递归求解。
考虑到辗转相减可以用辗转相除替代
b x 1 + a m o d b y 1 = gcd ( b , a m o d b ) bx_1+a\bmod by_1=\gcd(b,a\bmod b)
b x 1 + a m o d b y 1 = g cd( b , a m o d b )
由("/"是取整除)
a m o d b = a − a / b × b a\bmod b=a-a/b\times b
a m o d b = a − a / b × b
代入得
b x 1 + ( a − a / b × b ) y 1 = g c d ( b , a m o d b ) bx_1+(a-a/b\times b)y_1=gcd(b,a\bmod b)
b x 1 + ( a − a / b × b ) y 1 = g c d ( b , a m o d b )
等价于
a y 1 + b ( x 1 − a / b × y 1 ) = g c d ( a , b ) ay_1+b(x_1-a/b\times y_1)=gcd(a,b)
a y 1 + b ( x 1 − a / b × y 1 ) = g c d ( a , b )
得
x = y 1 , y = x 1 − a / b × y 1 x=y_1,y=x_1-a/b\times y_1
x = y 1 , y = x 1 − a / b × y 1
不断缩小规模最后 a = gcd ( a , b ) , b = 0 a=\gcd(a,b),b=0 a = g cd( a , b ) , b = 0 ,得方程 gcd ( a , b ) × x + 0 × y = gcd ( a , b ) \gcd(a,b)\times x+0\times y=\gcd(a,b) g cd( a , b ) × x + 0 × y = g cd( a , b ) ,得到一组特解 x = 1 , y = 0 x=1,y=0 x = 1 , y = 0 ,将这个方程反推回去可得原方程解。
1 2 3 4 5 6 7 8 9 10 int exgcd (int a, int b, int &x, int &y) { if (!b) { x = 1 , y = 0 ; return a; }else { int r = exgcd (b, a % b, y, x); y -= (a / b) * x; return r; } }
函数执行完毕后代码里面的 x , y x,y x , y 就是方程 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) a x + b y = g cd( a , b ) 的一组特解,通解的变化规律就是 x x x 和 y y y 的值往相反的方向变化,比如 x x x 变大一些 y y y 变小一些,为使得答案不变,设这个变化的最小单位值为 d 1 , d 2 d_1,d_2 d 1 , d 2 。
a ( x + d 1 ) + b ( y − d 2 ) = gcd ( a , b ) a(x+d_1)+b(y-d_2)=\gcd(a,b)
a ( x + d 1 ) + b ( y − d 2 ) = g cd( a , b )
a × d 1 = b × d 2 a\times d_1=b\times d_2
a × d 1 = b × d 2
同除 gcd ( a , b ) \gcd(a,b) g cd( a , b ) ,令 k 1 = a / gcd ( a , b ) , k 2 = b / gcd ( a , b ) k_1=a/\gcd(a,b),k_2=b/\gcd(a,b) k 1 = a / g cd( a , b ) , k 2 = b / g cd( a , b )
k 1 × d 1 = k 2 × d 2 k_1\times d_1 = k_2\times d_2
k 1 × d 1 = k 2 × d 2
k 1 , k 2 k_1,k_2 k 1 , k 2 互质,显然 d 1 = k 2 , d 2 = k 1 d_1=k_2,d_2=k_1 d 1 = k 2 , d 2 = k 1
故通解为
( x + k × d 1 , y − k × d 2 ) (x+k\times d_1,y-k\times d_2)
( x + k × d 1 , y − k × d 2 )
即
( x + k × b / gcd ( a , b ) , y − k × a / gcd ( a , b ) ) (x+k\times b/\gcd(a,b),y-k\times a/\gcd(a,b))
( x + k × b / g cd( a , b ) , y − k × a / g cd( a , b ) )
欧拉函数
定义
欧拉函数 φ ( n ) \varphi(n) φ ( n ) 表示小于或者等于 n n n 的正整数中与 n n n 互质的数的数目, 例如 φ ( 8 ) = 4 \varphi(8) = 4 φ ( 8 ) = 4 , 因为 1 , 3 , 5 , 7 1,3,5,7 1 , 3 , 5 , 7 与 8 8 8 互质。
欧拉函数值
特殊的 φ ( 1 ) = 1 \varphi(1)=1 φ ( 1 ) = 1 , φ ( p ) = 1 \varphi(p)=1 φ ( p ) = 1 ,(p p p 是素数);若 n n n 是素数 p p p 的 k k k 次幂
φ ( n ) = φ ( p k ) = p k − p k − 1 = ( p − 1 ) ⋅ p k − 1 \varphi(n)=\varphi(p^k)=p^k-p^{k-1}=(p-1)\cdot p^{k-1}
φ ( n ) = φ ( p k ) = p k − p k − 1 = ( p − 1 ) ⋅ p k − 1
相当于总数减去 p 的倍数。利用类似的想法我们考虑求 φ ( p 1 k 1 ⋅ p 2 k 2 ) \varphi(p_1^{k_1}\cdot p_2^{k_2}) φ ( p 1 k 1 ⋅ p 2 k 2 ) ,通过简单容斥我们知道,它应该等于总数减去 p 1 p_1 p 1 的倍数 p 2 p_2 p 2 的倍数,再加上 p 1 , p 2 p_1,p_2 p 1 , p 2 的倍数
φ ( p 1 k 1 ⋅ p 2 k 2 ) = p 1 k 1 ⋅ p 2 k 2 − p 1 k 1 − 1 ⋅ p 2 k 2 − p 1 k 1 ⋅ p 2 k 2 − 1 + p 1 k 1 − 1 ⋅ p 2 k 2 − 1 = ( p 1 k 1 − p 1 k 1 − 1 ) ( p 2 k 2 − p 2 k 2 − 1 ) \begin{aligned}
\varphi(p_1^{k_1}\cdot p_2^{k_2})&=p_1^{k_1}\cdot p_2^{k_2}-p_1^{k_1-1}\cdot p_2^{k_2}-p_1^{k_1}\cdot p_2^{k_2-1}+p_1^{k_1-1}\cdot p_2^{k_2-1}\\
&=\left(p_1^{k_1}-p_1^{k_1-1}\right)\left(p_2^{k_2}-p_2^{k_2-1}\right)
\end{aligned}
φ ( p 1 k 1 ⋅ p 2 k 2 ) = p 1 k 1 ⋅ p 2 k 2 − p 1 k 1 − 1 ⋅ p 2 k 2 − p 1 k 1 ⋅ p 2 k 2 − 1 + p 1 k 1 − 1 ⋅ p 2 k 2 − 1 = ( p 1 k 1 − p 1 k 1 − 1 ) ( p 2 k 2 − p 2 k 2 − 1 )
而我们发现
φ ( p 1 k 1 ) ⋅ φ ( p 2 k 2 ) = ( p 1 k 1 − p 1 k 1 − 1 ) ( p 2 k 2 − p 2 k 2 − 1 ) \varphi\left(p_1^{k_1}\right)\cdot \varphi\left(p_2^{k_2}\right) = \left(p_1^{k_1}-p_1^{k_1-1}\right)\left(p_2^{k_2}-p_2^{k_2-1}\right)
φ ( p 1 k 1 ) ⋅ φ ( p 2 k 2 ) = ( p 1 k 1 − p 1 k 1 − 1 ) ( p 2 k 2 − p 2 k 2 − 1 )
即 φ ( p 1 k 1 ⋅ p 2 k 2 ) = φ ( p 1 k 1 ) ⋅ φ ( p 2 k 2 ) \varphi\left(p_1^{k_1}\cdot p_2^{k_2}\right)=\varphi\left(p_1^{k_1}\right)\cdot \varphi\left(p_2^{k_2}\right) φ ( p 1 k 1 ⋅ p 2 k 2 ) = φ ( p 1 k 1 ) ⋅ φ ( p 2 k 2 ) ,这体现了欧拉函数是积性函数的性质,
积性函数 : 对于两个互质的 n , m n,m n , m ,若 f ( n ⋅ m ) = f ( n ) ⋅ f ( m ) f(n\cdot m)=f(n)\cdot f(m) f ( n ⋅ m ) = f ( n ) ⋅ f ( m ) ,称 f f f 为积性函数
我们将 n n n 因式分解
n = p 1 k 1 p 2 k 2 ⋯ p r k r n=p_1^{k_1}p_2^{k_2}\dotsb p_r^{k_r}
n = p 1 k 1 p 2 k 2 ⋯ p r k r
φ ( n ) = ∏ i = 1 r p i k i − 1 ( p i − 1 ) = n ⋅ ∏ i = 1 r ( p i − 1 p i ) \varphi(n)=\prod_{i=1}^r p_i^{k_i-1}(p_i-1)=n\cdot \prod_{i=1}^r (\frac{p_i-1}{p_i})
φ ( n ) = i = 1 ∏ r p i k i − 1 ( p i − 1 ) = n ⋅ i = 1 ∏ r ( p i p i − 1 )
欧拉函数的性质
欧拉函数是积性函数,当正整数 m , n m,n m , n 互质时,φ ( m ⋅ n ) = φ ( m ) ⋅ φ ( n ) \varphi(m\cdot n) = \varphi(m)\cdot \varphi(n) φ ( m ⋅ n ) = φ ( m ) ⋅ φ ( n )
当n n n 是奇数时,φ ( 2 ⋅ n ) = φ ( n ) \varphi(2\cdot n) = \varphi(n) φ ( 2 ⋅ n ) = φ ( n )
φ ( n ) = φ ( n / p ) ⋅ p \varphi(n) = \varphi(n/p)\cdot p φ ( n ) = φ ( n / p ) ⋅ p , (p p p 能整除 n / p n/p n / p ),
φ ( n ) = φ ( n / p ) ⋅ ( p − 1 ) \varphi(n) = \varphi(n/p)\cdot (p−1) φ ( n ) = φ ( n / p ) ⋅ ( p − 1 ) , (p p p 与 n / p n/p n / p 互质,且 p p p 是质数)
∑ d ∣ n φ ( d ) = n \sum_{d|n} \varphi(d)=n ∑ d ∣ n φ ( d ) = n (n n n 等于它所有因子的欧拉函数之和)
性质 2 证明:φ ( 2 ) = 1 \varphi(2)=1 φ ( 2 ) = 1 ,再利用积性函数
性质 3 证明:可以利用上一小节最后一个式子来推
性质 4 证明:利用积性函数性质和φ ( p ) = p − 1 \varphi(p)=p-1 φ ( p ) = p − 1
性质 5 证明:设 f ( n ) = ∑ d ∣ n φ ( d ) f(n)=\sum_{d|n}\varphi(d) f ( n ) = ∑ d ∣ n φ ( d ) ,令 n , m n,m n , m 互质
f ( n m ) = ∑ d ∣ n m φ ( d ) = ∑ d 1 ∣ n φ ( d 1 ) ⋅ ∑ d 2 ∣ m φ ( d 2 ) = f ( n ) ⋅ f ( m ) f(nm)=\sum_{d|nm}\varphi(d)=\sum_{d_1|n}\varphi(d_1)\cdot \sum_{d_2|m}\varphi(d_2)=f(n)\cdot f(m)
f ( n m ) = d ∣ n m ∑ φ ( d ) = d 1 ∣ n ∑ φ ( d 1 ) ⋅ d 2 ∣ m ∑ φ ( d 2 ) = f ( n ) ⋅ f ( m )
(因为 n , m n,m n , m 互质,那么它们的因子也相互质,故 n m nm n m 的因子可以看出 n n n 的因子乘上 m m m 的因子)
所有 f ( n ) f(n) f ( n ) 是积性函数
f ( p c ) = ∑ d ∣ p c φ ( d ) = φ ( 1 ) + φ ( p ) + φ ( p 2 ) + … + φ ( p c ) = p c f(p^c)=\sum_{d|p^c} \varphi(d)=\varphi(1)+\varphi(p)+\varphi(p^2)+\dotsc +\varphi(p^c)=p^c
f ( p c ) = d ∣ p c ∑ φ ( d ) = φ ( 1 ) + φ ( p ) + φ ( p 2 ) + … + φ ( p c ) = p c
因此
f ( n ) = ∏ i = 1 r f ( p i c i ) = ∏ i = 1 r p i c i = n f(n)=\prod_{i=1}^r f(p_i^{c_i})=\prod_{i=1}^r p_i^{c_i}=n
f ( n ) = i = 1 ∏ r f ( p i c i ) = i = 1 ∏ r p i c i = n
代码实现
法一 :利用定义 φ ( n ) = n ⋅ ∏ i = 1 r ( p i − 1 p i ) \displaystyle\varphi(n)=n\cdot \prod_{i=1}^r (\frac{p_i-1}{p_i}) φ ( n ) = n ⋅ i = 1 ∏ r ( p i p i − 1 ) ,通过普通筛求
1 2 3 4 5 6 7 8 9 10 void init (int n) { varphi[1 ] = 1 ; for (int i = 2 ; i <= n; i++) varphi[i] = i; for (int i = 2 ; i <= n; i++) { if (varphi[i] = i) for (int j = i; j <= n; j += i) varphi[j] = varphi[j] / i * (i - 1 ); } }
法二 :线性筛递推,利用性质 3 性质 4 : φ ( n ) = φ ( n / p ) ⋅ p \varphi(n) = \varphi(n/p)\cdot p φ ( n ) = φ ( n / p ) ⋅ p , (p p p 能整除 n / p n/p n / p ) ; φ ( n ) = φ ( n / p ) ⋅ ( p − 1 ) \varphi(n) = \varphi(n/p)\cdot (p−1) φ ( n ) = φ ( n / p ) ⋅ ( p − 1 ) , ( p p p 与 n / p n/p n / p 互质,且 p p p 是质数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void init (int n) { for (int i = 2 ; i <= n; i++) { if (!flag[i]) { p[tot++] = i; varphi[i] = i - 1 ; } for (int j = 0 ; j < tot; j++) { if (i * p[j] > n) break ; flag[i * p[j]] = 1 ; if (i % p[j] == 0 ) { varphi[i * p[j]] = varphi[i] * p[j]; break ; } varphi[i * p[j]] = varphi[i] * (p[j] - 1 ); } } }
法三 :利用性质 5 ∑ d ∣ n φ ( d ) = n \sum_{d|n} \varphi(d)=n ∑ d ∣ n φ ( d ) = n
1 2 3 4 5 6 7 void init (int n) { for (int i = 1 ; i <= n; i++) varphi[i] = i; for (int i = 1 ; i <= n; i++) { for (int j = i + i; j <= n; j += i) varphi[j] -= varphi[i]; } }
欧拉定理
欧拉定理的定义是:如果 a , n a,n a , n 为正整数,且 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 则有:
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1 \pmod{n}
a φ ( n ) ≡ 1 ( m o d n )
证明
令集合
S = { x 1 , x 2 , … , x φ ( n ) } S=\left\{ x_1,x_2,\dots,x_{\varphi(n)}\right\}
S = { x 1 , x 2 , … , x φ ( n ) }
表示所有的小于 n n n 并且与 n n n 互质的数;再令集合
T = { a ⋅ x 1 m o d n , a ⋅ x 2 m o d n , … , a ⋅ x φ ( n ) m o d n } T=\left\{a\cdot x_1\bmod n,a\cdot x_2\bmod n,\dots,a\cdot x_{\varphi(n)}\bmod n\right\}
T = { a ⋅ x 1 m o d n , a ⋅ x 2 m o d n , … , a ⋅ x φ ( n ) m o d n }
由于 gcd ( a , n ) = 1 , gcd ( x i , n ) = 1 \gcd(a,n) = 1,\gcd(x_i,n) = 1 g cd( a , n ) = 1 , g cd( x i , n ) = 1 , 所以 gcd ( a ⋅ x i , n ) = 1 \gcd(a\cdot x_i,n) = 1 g cd( a ⋅ x i , n ) = 1 ,所以
gcd ( a ⋅ x i m o d n , n ) = 1 \gcd(a\cdot x_i\bmod n,n) = 1
g cd( a ⋅ x i m o d n , n ) = 1
容易通过反证得出 T T T 中的元素是两两不相同的,因此集合 S S S 跟 T T T 是相同的,所以我们构造出
a φ ( n ) ⋅ x 1 ⋅ x 2 ⋅ … ⋅ x φ ( n ) ( m o d n ) ≡ a ⋅ x 1 ⋅ a ⋅ x 2 ⋅ … ⋅ a ⋅ x φ ( n ) ( m o d n ) ≡ x 1 ⋅ x 2 ⋅ … ⋅ x φ ( n ) ( m o d n ) \begin{aligned}
&\;a^{\varphi(n)}\cdot x_1\cdot x_2\cdot\dotso\cdot x_{\varphi(n)}& \pmod{n} \\
\equiv& \;a\cdot x_1 \cdot a \cdot x_2 \cdot \dotso \cdot a \cdot x_{\varphi(n)} &\pmod{n} \\
\equiv& \;x_1 \cdot x_2 \cdot \dotso \cdot x_{\varphi(n)} &\pmod{n}
\end{aligned}
≡ ≡ a φ ( n ) ⋅ x 1 ⋅ x 2 ⋅ … ⋅ x φ ( n ) a ⋅ x 1 ⋅ a ⋅ x 2 ⋅ … ⋅ a ⋅ x φ ( n ) x 1 ⋅ x 2 ⋅ … ⋅ x φ ( n ) ( m o d n ) ( m o d n ) ( m o d n )
所有 a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1 \pmod{n} a φ ( n ) ≡ 1 ( m o d n ) ,欧拉定理得证。
扩展欧拉定理
a b ≡ { a b m o d φ ( p ) , gcd ( a , p ) = 1 a b , gcd ( a , p ) ≠ 1 , b < φ ( p ) a b m o d φ ( p ) + φ ( p ) , gcd ( a , p ) ≠ 1 , b ≥ φ ( p ) ( m o d p ) a^b\equiv
\begin{cases}
a^{b\bmod\varphi(p)},\,&\gcd(a,\,p)=1\\
a^b,&\gcd(a,\,p)\ne1,\,b<\varphi(p)\\
a^{b\bmod\varphi(p)+\varphi(p)},&\gcd(a,\,p)\ne1,\,b\ge\varphi(p)
\end{cases}
\pmod p
a b ≡ ⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧ a b m o d φ ( p ) , a b , a b m o d φ ( p ) + φ ( p ) , g cd( a , p ) = 1 g cd( a , p ) = 1 , b < φ ( p ) g cd( a , p ) = 1 , b ≥ φ ( p ) ( m o d p )
一个应用
求最小的 k k k 满足 a k ≡ 1 ( m o d n ) a^k \equiv 1 \pmod{n} a k ≡ 1 ( m o d n ) ,k k k 一定是 φ ( n ) \varphi(n) φ ( n ) 的因子
费马小定理
费马小定理是欧拉定理的特殊情况,即当 p p p 为素数时
a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1\pmod{p}
a p − 1 ≡ 1 ( m o d p )
乘法逆元
当我们要计算 a b m o d c \dfrac{a}{b} \bmod c b a m o d c 时,又因为 a , b a,b a , b 很大,不能用高精保存时,典型的例子就是高精取模。这个时候我们可以用到乘法逆元,将除法转换成乘法并提前取模。
解不定方程
设:
i n v ⋅ b ≡ 1 ( m o d c ) inv\cdot b\equiv 1 \pmod{c}
i n v ⋅ b ≡ 1 ( m o d c )
我们称 i n v inv i n v (也可以记 b − 1 ( m o d c ) b^{-1}\pmod{c} b − 1 ( m o d c ) )为 b b b 对 c c c 的逆元,就可以将除法转化为乘法,即 a b m o d c = ( a ⋅ i n v ) m o d c \dfrac{a}{b}\bmod c=(a\cdot inv)\bmod c b a m o d c = ( a ⋅ i n v ) m o d c
那是否一定存在逆元呢?我们考虑下式
i n v ⋅ b ≡ 1 ( m o d c ) inv\cdot b\equiv 1 \pmod{c}
i n v ⋅ b ≡ 1 ( m o d c )
等价于
i n v ⋅ b + k ⋅ c = 1 inv\cdot b+k\cdot c=1
i n v ⋅ b + k ⋅ c = 1
b , c b,c b , c 是已知的,本质上是求上述的二元一次方程的一个正整数解,那么用扩展欧几里得就可以解决,若 gcd ( b , c ) = 1 \gcd(b,c)=1 g cd( b , c ) = 1 则有解,即存在逆元。
1 2 3 4 5 6 int inv (int b, int c) { int x, y; exgcd (b, c, x, y); x = (x % c + c) % c; return x; }
欧拉定理
特殊的,当 c c c 是质数时,可利用费马小定理
b c − 1 ≡ 1 ( m o d c ) b^{c-1}\equiv 1\pmod{c}
b c − 1 ≡ 1 ( m o d c )
同乘 i n v inv i n v
b c − 2 ≡ i n v ( m o d c ) b^{c-2}\equiv inv \pmod{c}
b c − 2 ≡ i n v ( m o d c )
所以 i n v = b c − 2 m o d c inv=b^{c-2}\bmod c i n v = b c − 2 m o d c ,用快速幂可以解决
稍微一般的,若 c c c 不是质数,可用欧拉定理
b φ ( c ) ≡ 1 ( m o d c ) b^{\varphi(c)}\equiv 1 \pmod{c}
b φ ( c ) ≡ 1 ( m o d c )
易得 i n v = b φ ( c ) − 1 m o d c inv=b^{\varphi(c)-1}\bmod c i n v = b φ ( c ) − 1 m o d c 。
线性求逆元
可以在 O ( n ) O(n) O ( n ) 的时间内求出 m o d p \bmod p m o d p 意义下(p p p 为质数),[ 1 , n ] [1,n] [ 1 , n ] 所有数的逆元。
令 p = i ⋅ d + r p=i\cdot d+r p = i ⋅ d + r ,其中 d = ⌊ p i ⌋ , r = p m o d i d=\lfloor\frac{p}{i}\rfloor,\;r=p\bmod i d = ⌊ i p ⌋ , r = p m o d i
那么有
i ⋅ d + r ≡ 0 ( m o d p ) i\cdot d + r \equiv 0 \pmod{p}
i ⋅ d + r ≡ 0 ( m o d p )
两边同乘 i − 1 r − 1 i^{-1}r^{-1} i − 1 r − 1
r − 1 ⋅ d + i − 1 ≡ 0 ( m o d p ) r^{-1}\cdot d + i^{-1} \equiv 0 \pmod{p}
r − 1 ⋅ d + i − 1 ≡ 0 ( m o d p )
得到
i − 1 ≡ − d ⋅ r − 1 ( m o d p ) i^{-1} \equiv -d \cdot r^{-1} \pmod{p}
i − 1 ≡ − d ⋅ r − 1 ( m o d p )
由于 r < i r<i r < i ,就可以从前往后推了。
1 2 inv[0 ] = inv[1 ] = 1 ; for (int i = 2 ; i <= n; ++i) inv[i] = (p - p / i) * inv[p % i] % p;
线性求任意 n 个数逆元
上面的方法只能求 [ 1 , n ] [1,n] [ 1 , n ] 的逆元,若求任意 n n n 个数 a i < p a_i < p a i < p ,可以这样。
记前缀积为 s i s_i s i ,用快速幂求出 s n s_n s n 的逆元 s n − 1 s_n^{-1} s n − 1 ,根据 s i − 1 = s i + 1 − 1 ⋅ a i + 1 s_{i}^{-1}=s_{i+1}^{-1}\cdot a_{i+1} s i − 1 = s i + 1 − 1 ⋅ a i + 1 可以得到任意 s i s_i s i 的逆元。
然后 a i − 1 = s i − 1 ⋅ s i − 1 a_{i}^{-1}=s_{i}^{-1}\cdot s_{i-1} a i − 1 = s i − 1 ⋅ s i − 1 即得所求。
复杂度 O ( n + log p ) O(n+\log p) O ( n + log p )
中国剩余定理
求解同余方程组。
给你如下同余方程组,求解 x x x
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) ⋮ x ≡ a n ( m o d m n ) \left\{\begin{aligned}
x &\equiv a_1 \pmod{m_1}\\
x &\equiv a_2 \pmod{m_2}\\
&\vdots\\
x &\equiv a_n \pmod{m_n}
\end{aligned}\right.
⎩ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎪ ⎪ ⎪ ⎧ x x x ≡ a 1 ( m o d m 1 ) ≡ a 2 ( m o d m 2 ) ⋮ ≡ a n ( m o d m n )
其中 m 1 , m 2 , … , m n m_1,m_2,\dotsc,m_n m 1 , m 2 , … , m n 两两互质,我们设
M = ∏ i = 1 n m i M=\prod_{i=1}^n m_i
M = i = 1 ∏ n m i
令
M i = M / m i M_i=M/m_i
M i = M / m i
s i s_i s i 是同余方程
M i × s i ≡ 1 ( m o d m i ) M_i\times s_i\equiv 1\pmod{m_i}
M i × s i ≡ 1 ( m o d m i )
的一个解,则同余方程组的解为
x = ∑ i = 1 n a i ⋅ M i ⋅ s i x=\sum_{i=1}^n a_i\cdot M_i\cdot s_i
x = i = 1 ∑ n a i ⋅ M i ⋅ s i
证明 :
由于 i ≠ j , gcd ( m i , m j ) = 1 i\ne j,\gcd(m_i,m_j)=1 i = j , g cd( m i , m j ) = 1 ,则 gcd ( M i , m i ) = 1 \gcd(M_i,m_i)=1 g cd( M i , m i ) = 1 ,故必然存在 s i s_i s i 为 M i M_i M i 对 m i m_i m i 的逆元。
考察乘积 a i s i M i a_is_iM_i a i s i M i 可知
a i s i M i ≡ a i ⋅ 1 ≡ a i ( m o d m i ) a_is_iM_i\equiv a_i\cdot 1\equiv a_i \pmod{m_i}
a i s i M i ≡ a i ⋅ 1 ≡ a i ( m o d m i )
∀ j ≠ i : a i s i M i ≡ 0 ( m o d m j ) \forall j\ne i:a_is_iM_i\equiv 0 \pmod{m_j}
∀ j = i : a i s i M i ≡ 0 ( m o d m j )
所以解 x = a 1 s 1 M 1 + a 2 s 2 M 2 + … + a n s n M n x=a_1s_1M_1+a_2s_2M_2+\dotsc+a_ns_nM_n x = a 1 s 1 M 1 + a 2 s 2 M 2 + … + a n s n M n 满足
x = a i s i M i + ∑ j ≠ i a j s j M j ≡ a i + ∑ j ≠ i 0 ≡ a i ( m o d m i ) x=a_is_iM_i+\sum_{j\ne i} a_js_jM_j\equiv a_i+\sum_{j\ne i} 0 \equiv a_i \pmod{m_i}
x = a i s i M i + j = i ∑ a j s j M j ≡ a i + j = i ∑ 0 ≡ a i ( m o d m i )
说明 x x x 就是方程的一个解。另外特解可以表示为
x + k ⋅ M x+k\cdot M
x + k ⋅ M
具体做法就是做 n n n 次 exgcd \operatorname{exgcd} e x g c d 求出 s i s_i s i ,再求出 x x x
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int crt (int n, int a[], int m[]) { int mul = 1 ; for (int i = 0 ; i < n; i++) { mul = mul * m[i]; } int ret = 0 ; for (int i = 0 ; i < n; i++) { int x, y; exgcd (mul / m[i], m[i], x, y); x = (x % m[i] + m[i]) % m[i]; ret += mul / m[i] * x * a[i]; ret %= mul; } return ret; }
END
Update 2021-3-27 : 修复了一些 bug,使公式表达更规范
Update 2021-7-17 : fix some bug, add something in 乘法逆元