众所周知,扩展欧几里得算法(下文统称Exgcd)能求解二元一次方程的整数解,乘法逆元、线性模方程等。本文我将简单的介绍该算法。
形如ax+by=gcd(a,b) 的方程,我们可以用Exgcd求出其最小整数解。我们考虑如何求解。
当b=0时,方程右边的值为a,那么显然可得x=1,y=0。
现在假设当前方程为ax1+by1=gcd(a,b),我们已经求得方程bx2+a%by2=gcd(a,b)的解为x2,y2,我们考虑通过x2,y2推出x1,y1的值、
解法如下:
因此,我们在gcd算法的代码上稍加改动,即可完成Exgcd的代码实现。
Exgcd算法的时间复杂度与gcd相等,最坏情况下近似于O(logn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int exgcd(int a, int b, int &x, int &y) { 5 if (b == 0) { 6 x = 1; y = 0; 7 return a; 8 } 9 int gcd = exgcd(b, a % b, x, y); 10 int x2 = x, y2 = y; 11 x = y2; 12 y = x2 - (a / b) * y2; 13 return gcd; 14 } 15 int main() { 16 int a, b, x, y; 17 scanf("%d%d", &a, &b); 18 exgcd(a, b, x, y); 19 printf("%d %d ", x, y); 20 return 0; 21 }
那么,我们来看看Exgcd的实际应用
1.求解线性模方程
引理:同余方程ax≡b(mod p)有解,当且仅当gcd(a,p)|b,在本题中,b=1,即gcd(a,p)=1;
变形,得到方程ax-py=gcd(a,p),这是Exgcd的一般形式,我们套用算法即可。
注意,本题要求出方程的最小正整数解,而Exgcd求出的是最小整数解,所以我们将答案加上p在mod p即可。
代码略
2.求解乘法逆元
乘法逆元的定义:当ax≡1 (mod p)且gcd(a,p)=1时,我们称a关于模p的逆元为x
这道题与上个例题非常相似,我们可以用同样的方法求解。
注意,在洛谷上本题数据范围较大,使用Exgcd总的时间复杂度为O(nlogn),不能通过本题。
求多个数的乘法逆元存在一种线性递推的方法可以在O(n)的时间内解决,由于本博客主要讲解Exgcd,所以不再赘述。