首先引入一个叫做贝祖定理的东西
对于 ∀a,b∈N,总是∃x,y∈Z,使ax+by=(a,b)
已知 a,b ,求 ax+by=(a,b) 一组可行解的算法即为扩展欧几里得算法。
首先我们知道用来求最大公因数的欧几里得算法。
int gcd(int a,int b)
{
if (!b) return a;
else return gcd(b,a/b)
}
扩展欧几里得其实是在欧几里得算法的基础上运行的,时间复杂度也在 log 级别。
假设现在 ax+by=(a,b) ,那么 (b,a%b)=(a,b) ,所以 bx+(a%b)y=(a,b)
又因为 a%b=a−(a/b)∗b ,所以
(a,b)=bx+(a−(a/b)∗b)y=bx+ay−(a/b)∗b∗y=ay+b(x−(a/b)∗y)
由此可以知道下一组满足条件的解为 x′=y,y′=x−(a/b)∗y
当b=0时,即a为最大公因数。这时只需要保证a的系数即x=1即可,y取任意值都不影响,不妨设y=0。
这就是整个扩展欧几里得算法的过程。
int exgcd(int a,int b,int &x,int &y)
{
if (!b)
{
x=1,y=0;
return a;
}
int ans=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-(a/b)*y;
return ans;
}
其实扩展欧几里得还有更简单的写法(from fye)
void exgcd(int a,int b,int &x,int &y,int &d)
{
if (!b) x=0,y=1,d=a;
else exgcd(b,a%b,y,x),y-=(a/b)*x;
}
实际上,在用exgcd解决问题的时候还有一些问题。
比如要求 ax+by=c 的值,首先可以将等式两遍同时除以 (a,b) ,如果不能整除则无解,因为c无论如何不为ab的倍数。
那么现在等式变成了 a′x+b′y=c′,(a′,b′)=1 ,为了满足扩欧的条件使 a′x+b′y=(a′,b′)=1 ,可以将等式两遍同时除以c,得到 axc+byc=1 。这样就可以直接利用exgcd求出 xc 和 yc 的值,然后再乘回去就可以了。
还有就是,用exgcd求出来的想x,y满足这样的性质 {|x|+|y|}min ,证明戳这里
求出来可行解了之后再将x不断-b/(a,b),y不断+a/(a,b),解仍然成立。
ax≡1(modp),(a,p)=1 ,则x为a的逆元。
将等式化简即可得到 ax−py=1 ,即为exgcd的经典模型。