无极之地
WUJI
无极之地。记录所思所见,慢慢写下去。
威尔逊定理:(p-1)! ≡ -1 (mod p)
世界时钟 北京 --:--:-- 东京 --:--:-- UTC --:--:-- 伦敦 --:--:-- 纽约 --:--:-- 算 2 100 m o d 13 2^{100} \bmod 13 2 100 mod 13 时,把一百个 2 2 2 乘开再取模当然不行。欧拉定理和费马小定理看起来只是在说「某个幂次同余 1 1 1 」,真正要回答的却是:指数太大时,幂可以怎么降,以及什么时候不能降。下面把定理、初等证明、手算和代码放在一起。
一次同余关心的是乘法能不能反过来;这两个定理关心的是乘法重复很多次以后会不会回到 1 1 1 。两件事在互素时碰到一起:能回到 1 1 1 ,就有逆,指数也才能安全地缩短。
欧拉函数先记清
对正整数 ,欧拉函数 表示 里与 互素的个数。例如 , , (只有 ), ( )。
1 , 2 , … , n 1,2,\dots,n 1 , 2 , … , n φ ( 10 ) = 4 \varphi(10)=4 φ ( 10 ) = 4 φ ( 15 ) = 8 \varphi(15)=8 φ ( 15 ) = 8 1 , 2 , 4 , 7 , 8 , 11 , 13 , 14 1,2,4,7,8,11,13,14 1 , 2 , 4 , 7 , 8 , 11 , 13 , 14 常用公式:若 n = p 1 k 1 ⋯ p r k r n=p_1^{k_1}\cdots p_r^{k_r} n = p 1 k 1 ⋯ p r k 是素因子分解,则
φ ( n ) = n ∏ i = 1 r ( 1 − 1 p i ) \varphi(n)=n\prod_{i=1}^{r}\Bigl(1-\frac{1}{p_i}\Bigr) φ ( n ) = n i = 1 ∏ r ( 1 − p 素数 p p p 时 φ ( p ) = p − 1 \varphi(p)=p-1 φ ( p ) = p − 1 。素幂更好记:φ ( p k ) = p k − p k − 1 \varphi(p^k)=p^k-p^{k-1} φ ( p k ) = p ,也就是丢掉那些被 整除的数。两个互素的正整数还满足 。
φ ( 8 ) = 4 , φ ( 9 ) = 6 , φ ( 12 ) = 4 , φ ( 14 ) = 6 \varphi(8)=4,\quad \varphi(9)=6,\quad \varphi(12)=4,\quad \varphi(14)=6 φ ( 8 ) = 4 , φ ( 9 ) = 6 , φ ( 12 ) = 4 , φ ( 14 ) = 6 φ ( 12 ) = 4 \varphi(12)=4 φ ( 12 ) = 4 容易算错。12 = 2 2 ⋅ 3 12=2^2\cdot 3 12 = 2 2 ⋅ 3 ,所以 φ ( 12 ) = 12 ⋅ ( 1 − 1 / 2 ) ⋅ ( 1 − 1 / 3 ) = 4 \varphi(12)=12\cdot(1-1/2)\cdot(1-1/3)=4 φ ( 12 ) ,既约剩余只有 。再算一个: , 。后面降幂,指数要模的就是这个 。它不是「循环节的最小长度」,只是一个保证能整除循环节的上界。同一个模下,不同底数的真实周期可以不同,但都整除 。
两个定理 欧拉定理。 若 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 ( mod n ) 费马小定理。 若 p p p 是素数且 p ∤ a p\nmid a p ∤ a ,则
a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1\pmod p a p − 1 ≡ 1 ( mod p ) 费马是欧拉的特例:素数模上 φ ( p ) = p − 1 \varphi(p)=p-1 φ ( p ) = p − 1 ,而 p ∤ a p\nmid a p ∤ a 正好就是 gcd ( a , p ) = 1 \gcd(a,p)=1 g cd( a , p ) = 1 。有时也写成 a p ≡ ,这一式对 也成立,因为两边都是 。后一种写法看起来更宽,却不能推广到合数模,后面易错一节会对照。
两个定理都要求「底数和模互素」。缺了这一条,a φ ( n ) ≡ 1 a^{\varphi(n)}\equiv 1 a φ ( n ) ≡ 1 可以立刻失败。互素保证 a a a 在模 n n n 下可逆,乘法才像在一个封闭的集合里打转,而不是慢慢掉进被 n n n 的素因子吸住的轨道。
为什么成立:剩余系相乘 证明不必上群论。核心是:与 n n n 互素的剩余,乘上一个也与 n n n 互素的 a a a ,只是被重新排了一遍。
设 n > 1 n>1 n > 1 ,把模 n n n 下与 n n n 互素的剩余列出来,共 φ ( n ) \varphi(n) φ ( n ) 个:
r 1 , r 2 , … , r φ ( n ) r_1,r_2,\dots,r_{\varphi(n)} r 1 , r 2 , … , r φ ( n ) 这就是一组既约剩余系。因为 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 ,每个 a r i ar_i a r i 仍与 n n n 互素:公共素因子既不能来自 a a a ,也不能来自 r i r_i 。它们还两两不同余:若 ,则 ;再由 得到 ,也就是 。于是
a r 1 , a r 2 , … , a r φ ( n ) ar_1,ar_2,\dots,ar_{\varphi(n)} a r 1 , a r 2 , … , a r φ ( n ) 也是一组既约剩余系,只是顺序不同。两边各自相乘,模 n n n 应当相等:
a φ ( n ) r 1 r 2 ⋯ r φ ( n ) ≡ r 1 r 2 ⋯ r φ ( n ) ( m o d n ) a^{\varphi(n)}\,r_1 r_2\cdots r_{\varphi(n)}\equiv r_1 r_2\cdots r_{\varphi(n)}\pmod n a φ ( n ) r 1 r 2 乘积 P = r 1 ⋯ r φ ( n ) P=r_1\cdots r_{\varphi(n)} P = r 1 ⋯ r φ ( n ) 本身也与 n n n 互素,因而有逆。两边同乘 P − 1 P^{-1} ,就得到
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1\pmod n a φ ( n ) ≡ 1 ( mod n ) 素数模时,既约剩余系就是 1 , 2 , … , p − 1 1,2,\dots,p-1 1 , 2 , … , p − 1 ,同一论证给出 a p − 1 ≡ 1 a^{p-1}\equiv 1 a p − 1 ≡ 1 。
用 n = 10 n=10 n = 10 、a = 3 a=3 a = 3 把重排看清楚。既约剩余是 1 , 3 , 7 , 9 1,3,7,9 1 , 3 , 7 , 9 。乘 3 3 3 之后变成
3 , 9 , 21 ≡ 1 , 27 ≡ 7 ( m o d 10 ) 3,9,21\equiv 1,\ 27\equiv 7\pmod{10} 3 , 9 , 21 ≡ 1 , 27 ≡ 7 ( mod 10 ) 也就是 3 , 9 , 1 , 7 3,9,1,7 3 , 9 , 1 , 7 ,还是那四个数。两边相乘:
3 4 ⋅ ( 1 ⋅ 3 ⋅ 7 ⋅ 9 ) ≡ 1 ⋅ 3 ⋅ 7 ⋅ 9 ( m o d 10 ) 3^4\cdot(1\cdot 3\cdot 7\cdot 9)\equiv 1\cdot 3\cdot 7\cdot 9\pmod{10} 3 4 ⋅ ( 1 ⋅ 3 ⋅ 7 ⋅ 9 ) ≡ 1 ⋅ 3 ⋅ 7 右边乘积是 189 ≡ 9 189\equiv 9 189 ≡ 9 ,与 10 10 10 互素,可以约掉,留下 3 4 ≡ 1 ( m o d 10 ) 3^4\equiv 1\pmod{10} 3 4 ≡ 1 ( mod 10 ) 。这就是欧拉定理的一个具体实例。
群论的说法更短:模 n n n 的既约剩余构成乘法群,阶为 φ ( n ) \varphi(n) φ ( n ) ,于是每个元素的阶整除群阶。上面的相乘论证,其实就是在初等语言里把这件事写出来。不必先学群,也能把「为什么幂会回到 1 1 1 」讲完。关键步骤只有三件:乘 a a a 仍落在既约剩余里、乘完只是重排、乘积 P P P 可约。任何一步依赖 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) ,所以前提不是装饰。
降幂:指数先模 φ ( n ) \varphi(n) φ ( n ) 若 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 且 k ≥ 0 k\ge 0 k ≥ 0 ,由欧拉定理立刻有
a k = a q ⋅ φ ( n ) + r = ( a φ ( n ) ) q ⋅ a r ≡ a r ( m o d n ) a^k = a^{q\cdot\varphi(n)+r} = \bigl(a^{\varphi(n)}\bigr)^q\cdot a^r \equiv a^r\pmod n a k = a q ⋅ φ ( n ) + r = ( a 其中 r = k m o d φ ( n ) r=k\bmod\varphi(n) r = k mod φ ( n ) 。也就是说,底数先收进 [ 0 , n ) [0,n) [ 0 , n ) ,指数再模 φ ( n ) \varphi(n) φ ( n ) 。注意 r r 取在 到 之间;若 恰好是 的倍数,余数是 ,这时应回到 ,不要写成 再忘了核对前提。
更细一点:真正最小的循环节是 a a a 模 n n n 的阶,记作 o r d n ( a ) \mathrm{ord}_n(a) ord n ( a ) ,它整除 φ ( n ) \varphi(n) φ ( n ) ,但不一定等于 φ ( n ) \varphi(n) φ ( 。手算时用 已经够把指数压下来;若还想再短,可以继续试 的因子。竞赛里除非明确要最小阶,否则不必硬找。
例一:费马降幂 算 2 100 m o d 13 2^{100}\bmod 13 2 100 mod 13 。13 13 13 是素数且不整除 2 2 2 ,所以 2 12 ≡ 1 ( m o d 13 ) 2^{12}\equiv 1\pmod{13} 2 。
100 = 8 ⋅ 12 + 4 ⟹ 2 100 = ( 2 12 ) 8 ⋅ 2 4 ≡ 1 8 ⋅ 16 ≡ 3 ( m o d 13 ) 100=8\cdot 12+4\implies 2^{100}=(2^{12})^8\cdot 2^4\equiv 1^8\cdot 16\equiv 3\pmod{13} 100 = 8 ⋅ 12 + 4 ⟹ 2 100 = ( 2 验算小的:2 4 = 16 ≡ 3 2^4=16\equiv 3 2 4 = 16 ≡ 3 ,对。若愿意再缩,会发现 2 12 2^{12} 2 12 的阶其实是 12 12 12 本身,这里已经不能更短。
再算一个稍大的:5 33 m o d 17 5^{33}\bmod 17 5 33 mod 17 。17 17 17 是素数,5 5 5 不被它整除,φ ( 17 ) = 16 \varphi(17)=16 φ ( 17 ) = 16 。
33 = 2 ⋅ 16 + 1 ⟹ 5 33 = ( 5 16 ) 2 ⋅ 5 ≡ 5 ( m o d 17 ) 33=2\cdot 16+1\implies 5^{33}=(5^{16})^2\cdot 5\equiv 5\pmod{17} 33 = 2 ⋅ 16 + 1 ⟹ 5 33 = ( 5 指数多出来的正好是 1 1 1 ,结果就是底数自己。这类题如果不先模 16 16 16 ,很容易在中间平方时算乱。
例二:合数模用欧拉 算 3 100 m o d 10 3^{100}\bmod 10 3 100 mod 10 。gcd ( 3 , 10 ) = 1 \gcd(3,10)=1 g cd( 3 , 10 ) = 1 ,φ ( 10 ) = 4 \varphi(10)=4 φ ( 10 ) = ,故 。
100 = 25 ⋅ 4 ⟹ 3 100 = ( 3 4 ) 25 ≡ 1 ( m o d 10 ) 100=25\cdot 4\implies 3^{100}=(3^4)^{25}\equiv 1\pmod{10} 100 = 25 ⋅ 4 ⟹ 3 100 = ( 3 4 ) 个位是 1 1 1 ,和 3 3 3 的幂循环 3 , 9 , 7 , 1 3,9,7,1 3 , 9 , 7 , 1 一致。这就是「求一个数的个位」最常见的做法:模 10 10 10 ,再用 φ ( 10 ) = 4 \varphi(10)=4 φ ( 10 ) = 4 看循环。
再看 7 222 m o d 15 7^{222}\bmod 15 7 222 mod 15 。gcd ( 7 , 15 ) = 1 \gcd(7,15)=1 g cd( 7 , 15 ) = 1 ,φ ( 15 ) = 8 \varphi(15)=8 φ ( 15 ) = ,所以 。
222 = 27 ⋅ 8 + 6 ⟹ 7 222 ≡ 7 6 ( m o d 15 ) 222=27\cdot 8+6\implies 7^{222}\equiv 7^6\pmod{15} 222 = 27 ⋅ 8 + 6 ⟹ 7 222 ≡ 7 6 7 2 = 49 ≡ 4 7^2=49\equiv 4 7 2 = 49 ≡ 4 ,7 4 = ( 7 2 ) 2 ≡ 16 ≡ 1 7^4=(7^2)^2\equiv 16\equiv 1 7 4 = ( 7 2 ) 。等等, 已经是 了?再乘一次核对: , ,确实 。于是阶是 而不是 ,可以继续降:
7 6 = 7 4 ⋅ 7 2 ≡ 1 ⋅ 4 ≡ 4 ( m o d 15 ) 7^6=7^4\cdot 7^2\equiv 1\cdot 4\equiv 4\pmod{15} 7 6 = 7 4 ⋅ 7 2 ≡ 1 ⋅ 4 ≡ 4 欧拉给出合法的上界,具体数字还可能更小。先用 φ ( n ) \varphi(n) φ ( n ) 保证正确,再观察中间幂是否提前回到 1 1 1 ,两步都不矛盾。
算 7 12 m o d 13 7^{12}\bmod 13 7 12 mod 13 。φ ( 13 ) = 12 \varphi(13)=12 φ ( 13 ) = 12 ,指数恰好整除。正确结论是 7 12 ≡ 1 ( m o d 13 ) 7^{12}\equiv 1\pmod{13} 7 ,不是 碰巧对了就以为规则是「余 等于 」。若换成 本身,那是另一道题:指数已经是 ,不必再用定理。
差别在「谁的 0 0 0 」。k = 0 k=0 k = 0 是原指数,规定 a 0 = 1 a^0=1 a 0 = 1 (通常还要求 a a a 与模的关系另说)。k m o d φ ( n ) = 0 k\bmod\varphi(n)=0 且 ,表示原指数是 的正倍数,应当用 。写代码时更稳妥的做法是:先保证指数为正,再取 ;若取完是 ,用 而不是 。
例四:末两位 求 7 100 7^{100} 7 100 的末两位,就是 7 100 m o d 100 7^{100}\bmod 100 7 100 mod 100 。gcd ( 7 , 100 ) = 1 \gcd(7,100)=1 g cd( 7 , 100 ) = , ,于是
7 100 = ( 7 40 ) 2 ⋅ 7 20 ≡ 7 20 ( m o d 100 ) 7^{100}=(7^{40})^2\cdot 7^{20}\equiv 7^{20}\pmod{100} 7 100 = ( 7 40 ) 2 ⋅ 7 20 余下的 7 20 7^{20} 7 20 再用快速幂,不必碰「一百个 7 7 7 相乘」。末三位同理,模改成 1000 1000 1000 。模数变大时,φ ( n ) \varphi(n) φ ( n ) 仍然只负责缩指数,真正的乘法次数交给二进制平方。
模逆:费马倒过来就是除法 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 时,a x ≡ 1 ( m o d n ) ax\equiv 1\pmod n a x ≡ 1 ( mod n ) 有唯一解,这个解叫 a a a 模 n n 的逆元。欧拉定理直接给出一个显式公式:
a ⋅ a φ ( n ) − 1 = a φ ( n ) ≡ 1 ( m o d n ) a\cdot a^{\varphi(n)-1}=a^{\varphi(n)}\equiv 1\pmod n a ⋅ a φ ( n ) − 1 = a φ ( n ) ≡ 1 ( a − 1 ≡ a φ ( n ) − 1 ( m o d n ) a^{-1}\equiv a^{\varphi(n)-1}\pmod n a − 1 ≡ a φ ( n ) − 1 ( mod n ) a − 1 ≡ a p − 2 ( m o d p ) a^{-1}\equiv a^{p-2}\pmod p a − 1 ≡ a p − 2 ( mod p ) 例如求 3 3 3 模 7 7 7 的逆:3 5 = 243 3^{5}=243 3 5 = 243 。243 ÷ 7 = 34 ⋅ 7 + 5 243\div 7=34\cdot 7+5 243 ÷ 7 = 34 ⋅ 7 + ,故 。验算 。
合数模同样能用。求 3 3 3 模 10 10 10 的逆:φ ( 10 ) = 4 \varphi(10)=4 φ ( 10 ) = 4 ,于是 3 − 1 ≡ 3 3 = 27 ≡ 7 ( m o d 10 ) 3^{-1}\equiv 3^{3}=27\equiv 7\pmod{10} 3 − 1 ≡ 3 。验算 。求 模 的逆: ,故 。前面已经算过 ,所以 。 , ,于是逆是 。验算 。
有了逆,除法就变成乘法。例如解 3 x ≡ 4 ( m o d 7 ) 3x\equiv 4\pmod 7 3 x ≡ 4 ( mod 7 ) :先取 3 − 1 ≡ 5 3^{-1}\equiv 5 3 − 1 ≡ 5 ,再 x ≡ 5 ⋅ 4 = 20 ≡ 6 ( m o d 7 ) x\equiv 5\cdot 4=20\equiv 6\pmod 7 。这只覆盖互素、因而恰好一解的情形。分数同余也一样: 应读成 ,不是把整数除法的商硬塞进去。一般模数上,扩展欧几里得往往比快速幂更省事,也不依赖先算出 。费马 / 欧拉这条路的价值在于:当你已经在做大指数幂,或者模是素数、 很好算时,求逆可以和降幂用同一套快速幂。一次同余在不互素时有几个解、怎么找特解,是另一篇文章的事,这里不展开。
Python 快速幂 降幂把指数从 k k k 收到 φ ( n ) \varphi(n) φ ( n ) 量级,但 φ ( n ) \varphi(n) φ ( n ) 本身仍可能很大。二进制快速幂把乘法次数降到 O ( log k ) O(\log k) O ( log k ) 。想法是把指数写成二进制。以 3 13 m o d 10 3^{13}\bmod 10 3 为例, ,于是
3 13 = 3 8 ⋅ 3 4 ⋅ 3 1 3^{13}=3^8\cdot 3^4\cdot 3^1 3 13 = 3 8 ⋅ 3 4 ⋅ 3 1 只要不断平方得到 3 , 3 2 , 3 4 , 3 8 3,3^2,3^4,3^8 3 , 3 2 , 3 4 , 3 8 ,再按比特位拣出来相乘。每一步都立刻取模,中间数不会涨起来:
def modpow ( a : int , k : int , n : int ) -> int :
""" 计算 a^k mod n。要求 n > 0,k >= 0。 """
if n <= 0 or k < 0 :
raise ValueError ( " 模数须为正,指数须非负 " )
a %= n
result = 1
while k :
if k & 1 :
result = result * a % n
a = a * a % n
k >>= 1
Python 自带的 pow(a, k, n) 就是这件事,竞赛里直接用即可。自己写一遍,是为了看清:每次平方、遇到奇数位再乘一次,中间结果始终收在模 n n n 里。不要先算完 a k a^k a k 再 % n,那会在大指数时把整数撑得过大,也失去取模的意义。
有了 φ ( n ) \varphi(n) φ ( n ) ,欧拉降幂可以写成:
from math import gcd
def euler_phi ( n : int ) -> int :
""" 计算 φ(n)。 """
result , x = n , n
p = 2
while p * p <= x :
if x % p == 0 :
while x % p == 0 :
x //= p
result -= result // p
p += 1
if x > 1 :
result -=
euler_pow 里对「余数为 0 0 0 」的处理,对应前面例三:指数是 φ ( n ) \varphi(n) φ ( n ) 的正倍数时,应落到 a φ ( n ) ≡ 1 a^{\varphi(n)}\equiv 1 a φ ( n ) ≡ 1 ,而不是误用 a 0 a^0 a 0 。euler_phi 按素因子筛,时间大约是 ,对普通竞赛里的模数够用;若 到 以上,需要先分解再套公式。
定理的前提是 gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 。少检查这一条,降幂会算错,逆元也会不存在。这是这两个定理最常见的误用。
直接套公式会错 2 2 2 与 6 6 6 不互素,φ ( 6 ) = 2 \varphi(6)=2 φ ( 6 ) = 2 ,但
2 2 = 4 ≢ 1 ( m o d 6 ) 2^{2}=4\not\equiv 1\pmod 6 2 2 = 4 ≡ 1 ( mod 6 ) 2 2 2 的幂模 6 6 6 只能是 2 2 2 或 4 4 4 ,永远到不了 1 1 1 。所以不存在 2 2 2 模 6 6 6 的逆,也不能写 2 k ≡ 2 k m o d 。若有人把 收成 ,得到 ,而真值是 ,错得干净。
再看 4 2 m o d 6 4^{2}\bmod 6 4 2 mod 6 :4 2 = 16 ≡ 4 4^2=16\equiv 4 4 2 = 16 ≡ 4 ,而 4 φ ( 6 ) = 4 2 ≡ 4 ≠ 1 。同一类错误。根子在于:乘 不再是既约剩余系上的重排。模 的既约剩余只有 ,里面根本没有 。证明的第一步就已经走不下去。
再举一个竞赛里更像真题的:求 6 10 m o d 8 6^{10}\bmod 8 6 10 mod 8 。φ ( 8 ) = 4 \varphi(8)=4 φ ( 8 ) = 4 ,若误用欧拉会去算 6 10 m o d 4 = 6 2 = 36 ≡ 4 ( m o d 8 ) 6^{10\bmod 4}=6^{2}=36\equiv 4\pmod 8 。真值要直接看幂次: , , ,之后一直是 。所以 ,不是 。原因也很具体: ,每次多一个因子 ,而 ,三次就补齐,幂被 整除。互素检查一旦漏掉,答案可以错到另一个剩余类。
a p ≡ a ( m o d p ) a^p\equiv a\pmod p a p ≡ a ( mod p ) 对素数 p p p 确实恒成立,包括 p ∣ a p\mid a p ∣ a 。不要把它推广成 a n ≡ a ( :合数里这叫卡迈克尔条件,大多数 不满足。例如 。再如 , ,故 。看到「费马对所有 都对」就往合数上搬,是第二类常见笔误。
指数可以降,但模的不是 φ ( n ) \varphi(n) φ ( n ) 有时 gcd ( a , n ) > 1 \gcd(a,n)>1 g cd( a , n ) > 1 ,仍可能对某个更小的指数出现循环,那是 λ ( n ) \lambda(n) λ ( n ) (卡迈克尔函数)或直接观察幂次序列的事,不能默认模 φ ( n ) \varphi(n) φ ( n ) 。例如 2 2 2 模 8 8 8 :幂次是 ,从某次起钉在 ,谈不上模 的循环。竞赛里更常见的安全策略是:
先算 d = gcd ( a , n ) d=\gcd(a,n) d = g cd( a , n ) 。
d = 1 d=1 d = 1 ,才用欧拉 / 费马降指数。
d > 1 d>1 d > 1 ,不要降指数;直接快速幂,或先把 n n n 拆成素因子幂再中国剩余定理拼回来。拆开之后,在每个素幂上单独判断:要么已经互素,要么幂次高到把这个素因子吃完。
a a a 是 n n n 的倍数时更简单:a k ≡ 0 ( m o d n ) a^k\equiv 0\pmod n a k ≡ 0 ( mod n ) (k ≥ 1 k\ge 1 k ≥ )。例如 ,这时谈 没有意义。
求 φ ( n ) \varphi(n) φ ( n ) 本身也会错 降幂正确的前提是 φ ( n ) \varphi(n) φ ( n ) 算对。n = p k n=p^k n = p k 时是 p k − p k − 1 p^k-p^{k-1} p k − p ,不是 。 ,不是 ; ,而 。把合数模当成素数模,是另一类常见笔误。 不是 , ,若误用 也能凑到 ,但中间降幂的余数会偏。
还有一个隐蔽错误:指数很大、却以字符串或递推形式给出时,要先确认底数与模互素,才能把指数模 φ ( n ) \varphi(n) φ ( n ) 。题目若写成求 a b m o d n a^b\bmod n a b mod n 且 b b b 有上百位,标准做法是在互素时算 b m o d φ ( n ) b\bmod\varphi(n) b ;不互素就不能先缩 。
和一次同余的边界 互素时,欧拉定理给出逆,于是 a x ≡ b ( m o d n ) ax\equiv b\pmod n a x ≡ b ( mod n ) 变成一次乘法。不互素时,逆不存在,方程仍可能有解,判别靠 gcd ( a , n ) \gcd(a,n) g cd( a , n ) 是否整除 b b b ,解法走扩展欧几里得。那是线性同余自己的故事。欧拉 / 费马管的是乘法群里的幂:能降的指数、能写出的逆、以及前提失效时为什么必须停手。
手算时先问互素,再问 φ ( n ) \varphi(n) φ ( n ) ,最后才快速幂。这三步分开,定理就不会被当成万能的「指数随便模一模」。幂回到 1 1 1 ,是互素剩余系被重新排列之后的必然结果;一旦底数踏出这个集合,排列不再发生,公式也就到此为止。
r
i
1
)
k
−
p k − 1
φ ( m n ) = φ ( m ) φ ( n ) \varphi(mn)=\varphi(m)\varphi(n) φ ( mn ) = φ ( m ) φ ( n )
=
12 ⋅
( 1 −
1/2 ) ⋅
( 1 −
1/3 ) =
4
20 = 2 2 ⋅ 5 20=2^2\cdot 5 20 = 2 2 ⋅ 5 φ ( 20 ) = 20 ⋅ ( 1 − 1 / 2 ) ⋅ ( 1 − 1 / 5 ) = 8 \varphi(20)=20\cdot(1-1/2)\cdot(1-1/5)=8 φ ( 20 ) = 20 ⋅ ( 1 − 1/2 ) ⋅ ( 1 − 1/5 ) = 8 a ( m o d p ) a^p\equiv a\pmod p a p ≡ a ( mod p )
r i
a r i ≡ a r j ( m o d n ) ar_i\equiv ar_j\pmod n a r i ≡ a r j ( mod n ) n ∣ a ( r i − r j ) n\mid a(r_i-r_j) n ∣ a ( r i − r j ) gcd ( a , n ) = 1 \gcd(a,n)=1 g cd( a , n ) = 1 n ∣ ( r i − r j ) n\mid(r_i-r_j) n ∣ ( r i − r j ) r i ≡ r j r_i\equiv r_j r i ≡ r j
⋯
r φ ( n )
≡
r 1 r 2 ⋯ r φ ( n )
( mod n )
P
− 1
⋅
9
( mod 10 )
=
1
φ ( n )
) q
⋅
a r ≡
a r
( mod n )
r
a φ ( n ) ≡ 1 a^{\varphi(n)}\equiv 1 a φ ( n ) ≡ 1 n
)
12
≡
1
( mod 13 )
12
) 8
⋅
2 4 ≡
1 8 ⋅
16 ≡
3
( mod 13 )
16
) 2
⋅
5 ≡
5
( mod 17 )
4
3 4 ≡ 1 ( m o d 10 ) 3^4\equiv 1\pmod{10} 3 4 ≡ 1 ( mod 10 )
25
≡
1
( mod 10 )
8
7 8 ≡ 1 ( m o d 15 ) 7^8\equiv 1\pmod{15} 7 8 ≡ 1 ( mod 15 ) (
mod
15
)
2
≡
16 ≡
1
2401 = 160 ⋅ 15 + 1 2401=160\cdot 15+1 2401 = 160 ⋅ 15 + 1
( mod 15 )
12
≡
1
( mod 13 )
7 0 m o d 13 7^{0}\bmod 13 7 0 mod 13 k
mod
φ ( n ) =
0
a φ ( n ) ≡ 1 a^{\varphi(n)}\equiv 1 a φ ( n ) ≡ 1 k m o d φ ( n ) k\bmod\varphi(n) k mod φ ( n ) 1
φ ( 100 ) = 40 \varphi(100)=40 φ ( 100 ) = 40 ≡
7 20
( mod 100 )
n
mod
n
)
5
3 − 1 ≡ 5 ( m o d 7 ) 3^{-1}\equiv 5\pmod 7 3 − 1 ≡ 5 ( mod 7 ) 3 ⋅ 5 = 15 ≡ 1 3\cdot 5=15\equiv 1 3 ⋅ 5 = 15 ≡ 1 3
=
27 ≡
7
( mod 10 )
3 ⋅ 7 = 21 ≡ 1 3\cdot 7=21\equiv 1 3 ⋅ 7 = 21 ≡ 1 φ ( 15 ) = 8 \varphi(15)=8 φ ( 15 ) = 8 7 − 1 ≡ 7 7 ( m o d 15 ) 7^{-1}\equiv 7^{7}\pmod{15} 7 − 1 ≡ 7 7 ( mod 15 ) 7 7 = 7 4 ⋅ 7 3 ≡ 7 3 7^7=7^4\cdot 7^3\equiv 7^3 7 7 = 7 4 ⋅ 7 3 ≡ 7 3 7 3 ≡ 28 ≡ 13 7^3\equiv 28\equiv 13 7 3 ≡ 28 ≡ 13 7 ⋅ 13 = 91 = 6 ⋅ 15 + 1 7\cdot 13=91=6\cdot 15+1 7 ⋅ 13 = 91 = 6 ⋅ 15 + 1 x ≡ 5 ⋅ 4 = 20 ≡ 6 ( mod 7 )
2 / 3 m o d 7 2/3\bmod 7 2/3 mod 7 2 ⋅ 3 − 1 ≡ 2 ⋅ 5 ≡ 3 ( m o d 7 ) 2\cdot 3^{-1}\equiv 2\cdot 5\equiv 3\pmod 7 2 ⋅ 3 − 1 ≡ 2 ⋅ 5 ≡ 3 ( mod 7 ) 13
mod
10
13 = 1101 2 = 8 + 4 + 1 13=1101_2=8+4+1 13 = 110 1 2 = 8 + 4 + 1 return
result
result
//
x
return result
def euler_pow ( a : int , k : int , n : int ) -> int :
""" 在 gcd(a, n) = 1 时用欧拉定理降幂,再快速幂。 """
if n <= 0 or k < 0 :
raise ValueError ( " 模数须为正,指数须非负 " )
a %= n
if gcd ( a , n ) != 1 :
raise ValueError ( f " { a } 与 { n } 不互素,不能直接用欧拉降幂" )
phi = euler_phi ( n )
if k >= phi :
k = k % phi
if k == 0 :
k = phi
return modpow ( a , k , n )
def fermat_inv ( a : int , p : int ) -> int :
""" 素数模上 a^{-1} ≡ a^{p-2} (mod p)。 """
a %= p
if a == 0 :
raise ValueError ( " 0 没有逆元 " )
return modpow ( a , p - 2 , p )
if __name__ == " __main__ " :
print ( modpow ( 2 , 100 , 13 )) # 3
print ( euler_pow ( 3 , 100 , 10 )) # 1
print ( euler_pow ( 7 , 222 , 15 )) # 4
print ( fermat_inv ( 3 , 7 )) # 5
print ( euler_pow ( 3 , 3 , 10 )) # 7,也是 3 模 10 的逆
2 2^{k}\equiv 2^{k\bmod 2} 2 k ≡ 2 k mod 2
2 100 = ( 2 2 ) 50 = 4 50 ≡ 4 ( m o d 6 ) 2^{100}=(2^2)^{50}=4^{50}\equiv 4\pmod 6 2 100 = ( 2 2 ) 50 = 4 50 ≡ 4^{\varphi(6)}=4^2\equiv 4\neq 1 4 φ ( 6 ) = 4 2 ≡ 4 = 1
6 10 mod 4 = 6 2 = 36 ≡ 4 ( mod 8 )
6 2 = 36 ≡ 4 6^2=36\equiv 4 6 2 = 36 ≡ 4 6 3 = 216 ≡ 0 6^3=216\equiv 0 6 3 = 216 ≡ 0 m o d n ) a^n\equiv a\pmod n a n ≡ a ( mod n )
2 6 = 64 ≡ 4 ≢ 2 ( m o d 6 ) 2^6=64\equiv 4\not\equiv 2\pmod 6 2 6 = 64 ≡ 4 ≡ 2 ( mod 6 ) 2 15 = 32768 2^{15}=32768 2 15 = 32768 32768 − 2 = 32766 = 2184 ⋅ 15 + 6 32768-2=32766=2184\cdot 15+6 32768 − 2 = 32766 = 2184 ⋅ 15 + 6 2 15 ≢ 2 ( m o d 15 ) 2^{15}\not\equiv 2\pmod{15} 2 15 ≡ 2 ( mod 15 ) 2 , 4 , 0 , 0 , … 2,4,0,0,\dots 2 , 4 , 0 , 0 , …
1
10 100 m o d 10 = 0 10^{100}\bmod 10=0 1 0 100 mod 10 = 0 10 φ ( 10 ) 10^{\varphi(10)} 1 0 φ ( 10 )
k − 1
3 4 = 81 ≡ 1 ( m o d 8 ) 3^4=81\equiv 1\pmod 8 3 4 = 81 ≡ 1 ( mod 8 ) 3 1 = 3 ≢ 1 3^{1}=3\not\equiv 1 3 1 = 3 ≡ 1 2 6 = 64 ≡ 1 ( m o d 9 ) 2^6=64\equiv 1\pmod 9 2 6 = 64 ≡ 1 ( mod 9 )
mod
φ ( n )
4
( mod 6 )
欧拉定理与费马小定理 · 无极之地