逆元
若 a x = 1 ( mod p ) a x = 1 ( mod p ) ,那么称 a a 是 x x 的逆元,显然 x x 也是 a a 的逆元。
两边同时除以 a a 得到 x = 1 a ( mod p ) x = 1 a ( mod p ) ,可以写成 x = a − 1 ( mod p ) x = a − 1 ( mod p ) ,这么看来,乘法逆元就是取模意义下的倒数啊。
若 p p 为质数,0 0 没有逆元,1 1 的逆元是 1 1 ,p − 1 p − 1 的逆元是 p − 1 p − 1 。其他都是一对一对的逆元,证明可见「裴蜀定理」。
为啥 p − 1 = 1 p − 1 ( mod p ) p − 1 = 1 p − 1 ( mod p ) 呢?直观解释是负负得正 − 1 = 1 − 1 − 1 = 1 − 1 ,另一种解释是 1 = p 2 − 2 p + 1 = ( p − 1 ) 2 ( mod p ) 1 = p 2 − 2 p + 1 = ( p − 1 ) 2 ( mod p ) 。
暴力求解
a x = 1 ( mod p ) a x = 1 ( mod p ) 是个线性同余方程。解 x x 必然 ∈ [ 0 , p − 1 ] ∈ [ 0 , p − 1 ] ,所以直接暴力寻找可能的 x x 。
单次复杂度 O ( p ) O ( p ) 。
费马小定理
前置条件:p p 为质数。
求解 x x 就是计算 a − 1 a − 1 。
根据费马小定理,若 p p 为质数,则 a p − 1 = 1 ( mod p ) a p − 1 = 1 ( mod p ) ,将等式两边同时乘 a − 1 a − 1 就可以得到 a p − 2 = a − 1 a p − 2 = a − 1 ,快速幂求解。
单次复杂度 O ( log p ) O ( log p ) 。
欧拉定理
费马小定理可以看作欧拉定理的特殊情况。
根据欧拉定理,若 gcd ( a , p ) = 1 gcd ( a , p ) = 1 ,则 a φ ( p ) = 1 ( mod p ) a φ ( p ) = 1 ( mod p ) ,将等式两边同时乘 a − 1 a − 1 就可以得到 a φ ( p ) − 1 = a − 1 a φ ( p ) − 1 = a − 1 。
单次复杂度由 φ φ 的求解方法确定,从 O ( √ p ) ∼ O ( log p ) O ( p ) ∼ O ( log p ) 均有可能。
拓展欧几里得
a x = 1 ( mod p ) a x = 1 ( mod p ) 可以转化为 a x + p k = 1 a x + p k = 1 ,其中 a , p a , p 已知,需要求一组 x , k x , k 使得 x ∈ [ 0 , p − 1 ] x ∈ [ 0 , p − 1 ] 。
通过裴蜀定理可得存在一组 x , k x , k 使得 a x + p k = gcd ( a , p ) a x + p k = gcd ( a , p ) 。所以若 gcd ( a , p ) = 1 gcd ( a , p ) = 1 ,那么 a x + p k = 1 a x + p k = 1 必然有解。根据解的周期性可知必然存在一个解使得 x ∈ [ 0 , p − 1 ] x ∈ [ 0 , p − 1 ] 。所以逆元存在的充分条件是 gcd ( a , p ) = 1 gcd ( a , p ) = 1 。
求解 a x + p k = 1 a x + p k = 1 可以采用拓展欧几里得的方法求解。
前缀积
( n m ) = n ! m ! ( n − m ) ! ( n m ) = n ! m ! ( n − m ) ! ,类似的,1 a = ( a − 1 ) ! a ! 1 a = ( a − 1 ) ! a ! 。
通过前缀积预处理出 1 ! , 2 ! … ( a − 1 ) ! , a ! 1 ! , 2 ! … ( a − 1 ) ! , a ! ,求出 a ! a ! 的逆元 1 a ! 1 a ! ,再一路循环回去 1 i = i + 1 ( i + 1 ) ! 1 i = i + 1 ( i + 1 ) ! 就可以求出所有阶乘和阶乘的逆元。而且这个方法对于求 1 ∏ r i = l i , 1 ≤ l ≤ r < p 1 ∏ i = l r i , 1 ≤ l ≤ r < p 也是在常数时间内完成,
求出 [ 1 , n ] [ 1 , n ] 中所有逆元的复杂度是 O ( n + log p ) O ( n + log p ) 。
线性求逆元
p = 0 ( mod p ) ⌊ p a ⌋ × a + p mod a = 0 ( mod p ) ⌊ p a ⌋ p mod a + 1 a = 0 ( mod p ) 1 a = − ⌊ p a ⌋ p mod a ( mod p ) p = 0 ( mod p ) ⌊ p a ⌋ × a + p mod a = 0 ( mod p ) ⌊ p a ⌋ p mod a + 1 a = 0 ( mod p ) 1 a = − ⌊ p a ⌋ p mod a ( mod p )
发现要求出 1 a 1 a 必须得求出 1 p mod a 1 p mod a ,可以使用数组递推下去也可以直接递归求解。
求出 [ 1 , n ] [ 1 , n ] 中所有逆元的复杂度是 O ( n ) O ( n ) 。
若递归求解,已知时间复杂度上界为 O ( n 1 3 ) O ( n 1 3 ) ,下界为 Ω ( ln n ln ln n ) Ω ( ln n ln ln n ) 。有人猜想其复杂度为 O ( log 2 n ) O ( log 2 n ) 。不过在 int
范围内可以近似看作单 log log 倒是真的。
模数 p p
998244353 998244353
10 9 + 7 10 9 + 7
10 9 + 9 10 9 + 9
n = 10 6 n = 10 6 的递归次数
30 30
31 31
29 29
n = 10 7 n = 10 7 的递归次数
35 35
39 39
35 35
n = 10 8 n = 10 8 的递归次数
40 40
45 45
42 42
线性筛
若 t ∣ a t ∣ a ,那么 1 a = 1 t × 1 a t 1 a = 1 t × 1 a t 。
借助线性筛筛出 [ 1 , n ] [ 1 , n ] 的所有质数以及他们的逆元。在线性筛时,每个数 i i 只会被自己的最小质因子 mpf ( i ) mpf ( i ) 筛到,所以计算 1 mpf ( i ) × 1 i mpf ( i ) 1 mpf ( i ) × 1 i mpf ( i ) 就行了。
若求出 [ 1 , n ] [ 1 , n ] 中所有逆元,线性筛的复杂度为 O ( n ) O ( n ) ,只有 [ 1 , n ] [ 1 , n ] 中的质数需要计算逆元,质数个数约为 n ln n n ln n ,每个的计算复杂度为 log p log p ,所以总复杂度为 O ( n + n log p ln n ) O ( n + n log p ln n ) ,近似于线性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!