版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/westbrook1998/article/details/83870598
拓展欧几里德要解决的问题就是给定方程
ax+by==gcd(a,b),已知
a,b,求解
x,y且使
∣x∣+∣y∣最小,而且既然是欧几里德,顺便也能把
gcd(a,b)求出来
因此,拓展欧几里德也就可以解
ax+by==c这种方程了,虽然右边不是
gcd(a,b)但我们只要将得到的解乘以
gcd(a,b)c即可
下面讲一下拓展欧几里德算法的证明
首先已知
ax1+by1==gcd(a,b),如果把
a换成
b,
b换成
a%b,那么这个方程也还是成立的,也就是
bx2+(a%b)y2==gcd(b,a%b),然后我们由欧几里德可以知道
gcd(a,b)==gcd(b,a%b),那么上面的式子对应一下,就能得到
ax1+by1==bx2+(a%b)y2,然后
a%b又可以化成
a−⌊(ba)⌋b,那么就可以得到
ax1+by1==bx2+(a−⌊(ba)⌋b)y2,右边化简一下,把
ay2提到前面就是
ax1+by1==ay2+b(x2−⌊ba)⌋y2),这样对应一下,
x1=y2,y1=x2−⌊(ba)⌋y2,最后我们还要注意到递归的边界条件,当
b=0时,
gcd(a,b)=a,所以此时
x=1,y=0
所以就可以来写代码了
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return d;
}
一旦理解了算法,写起来就比较容易了
逆元,逆元其实就是在一个代数系统下类似与倒数的定义,我们在这里定义的就是模n下的逆元,比如
ab≡1(%n),如果不考虑这个同模的话,
a/b就是
b/a的倒数(逆元),现在有了模n的情况,就不叫倒数,叫逆元了
所以求逆元一般就是指已知
ab≡1(%n),给定
a/b,求
b/a,然后还有一个限制就是只有
a/b和
n互质时,才有对应的逆元
现在假设有
ax≡1(%n),给定
a,求
a的逆元
x,因为刚才说
a要和n互质时才有逆元,所以
gcd(a,n)≡1,所以有
ax+ny≡1,所以我们用拓展欧几里德求出
x即可,当然如果顺便得到的gcd值不为1,也就是两数不互质的话,就不存在逆元,返回-1
ll inv(ll a,ll m){
ll x,y;
ll d=exgcd(a,m,x,y);
if(d==1){
return (x%m+m)%m;
}
return -1;
}
拓展欧几里德还能用来解形如
ax+by==c的方程,其中有解的条件是
gcd(a,b)∣c,所以其实方法就是先通过拓展欧几里德解出方程
ax′+by′==gcd(a,b),然后
x=gcd(a,b)x′c,y=gcd(a,b)y′c,这得到的就是方程的一个特解,而通解就是
x0=x±gcd(a,b)kb,y0=y∓gcd(a,b)ka,其中
k为任意整数,这个证明怎么得来的呢,有个比较简单的理解,我们现在已知
ax+by==c的一个特解
x,y,那么通解代入的形式肯定是
a(x+???1)+b(y+???2)==c,对比一下可以得出
a???1+b???2==0,那显然就是用
gcd(a,b)做分母,分子包含另一个的k倍即可,然后符号相反,就比如
agcd(a,b)kb和
bgcd(a,b)−ka,这样凑齐来就是0了,因此这就是通解
然后很多情况下我们要求的是最小整数解,而且有时候有负数来捣乱,所以应该是
x=(x%abs(db)+abs(db))%abs(db)