欧几里得也就是辗转相除法是用来求a,b的最大公因数gcd(a,b)的,那么如果d是a,b的最大公因数,那么一点有ax+by=d。如何求解这个二元一次方程,就要用到扩展欧几里得了。
下面先给出程序
int e_gcd(int a,int b,int &x,int &y)//返回最大公因数
{
if(b==0)
x=1;y=0;return a;
int ans=e_gcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;//2
return ans;
}
为什么会有2这个式子呢?
我们从后往前推
最终的状态是x=1,y=0,b=0,a是最大公因数,那么初始状态呢?
我们知道第一次后gcd(a,b)==gcd(b,a%b)的,那么相应的ax+by==bx1+(a%b)y1==bx1+(a-a/b*b)y1
化简一下就是ay1+b(x1-a/b*y1) 那么我们就可以知道,第一次后x变成了y1,y变成了x1-a/b*y1。所以也就有了式子2
另一个问题是我们得到的解x0,y0是一个特解,其通解为x=x0+b/d*t ,y=y0-b/d*t 那么由此我们就可以得到最小的x解(x0%b/d+b/d)%b/d。这里考虑到不使解为负数的情况,所以加了求余函数。
相应的,我们可以求任意的模线性方程ax+by=c。先求出ax+by=gcd(a,b),如果gcd(a,b)是c的因子,方程有解,只需要在原解的情况下*c/gcd(a,b)就好
最小的x解怎么得到的呢?
a*x0+b*y0=gcd(a,b);
如果c%gcd==0 那么此方程有解,否则没有解
若有解
方程两边同时乘以 c/gcd(a,b) 得 (a*c/gcd(a,b))*x0+(b*c/gcd(a,b))*y0=c;
这时得出方程的一个解 x1=x0*c/gcd(a,b) y1=y0*c/gcd(a,b)
求最小整数解 意思把x1变到减少到不能减少为止 也就是把x0 减少到不能减少为止
若x0减小x,那么方程左边 整体会减少 (a*c/gcd(a,b))*x 此时 y0 需要增加相应的数使得等式平衡
而假设 y0增加了y 总体增加了 (b*c/gcd(a,b))*y 此时 (a*c/gcd(a,b))*x==(a*c/gcd(a,b))*y
而且x,y为整数 我们可以得到 x/y==b/gcd(a,b) / a/gcd(a,b)
这时 x每次减少 b/gcd(a,b) y只需增加 a/gcd(a,b) 就可以使得等式平衡。 那为什么我们不约掉gcd(a,b)?
因为x越小,我们得到的最小整数解就会越小。
2 应用:有扩展欧几里德求mod m的逆元
对于整数a,m,如果存在整数b,满足ab=1(mod m)(那个等号是三条线),那么称b是a的模m的乘法逆元。如果b存在,必有gcd(a,m)=1
求解方法可以调用扩展欧几里得
int mod_reverse(int a,int m)
{
int x,y;
int gcd=e_gcd(a,m,x,y);
if(gcd==1)
if(x<0) x=(x%m+m)%m;
return x;
else
return 0;
}