浅谈扩展欧几里得算法

众所周知,扩展欧几里得算法(下文统称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)

 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\n", x, y);    
20     return 0;
21 }
Exgcd

那么,我们来看看Exgcd的实际应用

1.求解线性模方程

参考例题【NOIP2012】同余方程

引理:同余方程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.求解乘法逆元

参考例题【洛谷3811】乘法逆元

乘法逆元的定义:当ax≡1 (mod p)且gcd(a,p)=1时,我们称a关于模p的逆元为x

这道题与上个例题非常相似,我们可以用同样的方法求解。

注意,在洛谷上本题数据范围较大,使用Exgcd总的时间复杂度为O(nlogn),不能通过本题。

求多个数的乘法逆元存在一种线性递推的方法可以在O(n)的时间内解决,由于本博客主要讲解Exgcd,所以不再赘述。

posted @ 2019-06-25 20:57  AD_shl  阅读(2040)  评论(2编辑  收藏  举报