扩展欧几里得与模逆元
一句话说明
扩展欧几里得不只是求
gcd(a,b),而是顺手求出一组x,y,使得ax + by = gcd(a,b)。
什么时候该想到它
- 要求模逆元,但模数不一定是质数
- 要解
ax + by = c - 要解线性同余方程
- 想同时拿到
gcd和系数解
为什么它成立
普通欧几里得用了:
gcd(a, b) = gcd(b, a mod b)而:
a mod b = a - floor(a/b) * b所以如果子问题已经知道:
g = b*x1 + (a mod b)*y1代回去就能得到:
g = a*y1 + b*(x1 - floor(a/b)*y1)于是:
x = y1y = x1 - (a/b)*y1
Go 模板:扩展欧几里得
func Exgcd(a, b int) (g, x, y int) {
if b == 0 {
return a, 1, 0
}
g, x1, y1 := Exgcd(b, a%b)
x = y1
y = x1 - (a/b)*y1
return g, x, y
}Go 模板:模逆元
如果 gcd(a, m) = 1,那么 a 在模 m 下存在逆元。
func ModInverse(a, m int) int {
g, x, _ := Exgcd(a, m)
if g != 1 {
return -1
}
x %= m
if x < 0 {
x += m
}
return x
}为什么 x 就是逆元
因为当 gcd(a,m)=1 时,扩展欧几里得会给出:
ax + my = 1两边对 m 取模:
ax ≡ 1 (mod m)所以 x 就是逆元。
一个很实用的结论
模逆元存在的前提是:
gcd(a, m) = 1如果不互质,就别再往“除法取模”上硬做了。
易错点
扩展欧几里得与模逆元最容易错的地方
- 回推公式里
x和y很容易写反。- 最终逆元要规范到
0..m-1范围。- 只有互质时逆元才存在。
复杂度
| 指标 | 复杂度 |
|---|---|
| 时间复杂度 | O(log min(a,b)) |
| 空间复杂度 | 递归写法 O(log min(a,b)) |
相关笔记
返回:数学算法