欧几里得算法
即利用辗转相除法求最大公因数
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
裴蜀定理(贝祖定理)
若a,b是整数,那么一定存在整数x,y,使ax+by=gcd(a,b)成立
重要推论:a和b互质的充要条件是存在整数x,y,有ax+by=1
扩展欧几里得算法
扩展欧几里得算法又称exgcd,就是利用欧几里得算法,求出贝祖定理ax+by=gcd(a,b)的整数解
证明:
∵gcd(a,b)=gcd(b,a%b),gcd(b,a%b)=bx+(a%b)y
∴a1x1+b1y1=gcd(a1,b1)=gcd(b1,a1%b1)=b1x2+(a1%b1)y2
令a2=b1,b2=a1%b1
∴a1x2+b2y2=gcd(a2,b2)=gcd(b2,a2%b2))=b2x3+(a2%b2)y3
同理…
最后可化简为gcd(an,0)=anxn+0*yn=an
得到最后一组解为xn=1,yn=0
∵a%b=a-a/b*b,其中a/b是计算机除法,不是数学意义的除法
在第一次我们化简的等式中有a1x1+b1y1=b1x2+(a1%b1)y2
∴a1x1+b1y1=b1x2+(a1-a1/b1*b1)y2=a1y2+b1(x2-a1/b1*y2)
∴x1=y2,y1=x2-a1/b1*y2
然后由最后一组解回溯,即可求得x1,y1
下面的代码中是简洁版本:我们都是由下一层得到上一层的,当我们由最后一层返回倒数第二层的时候,我们把y传给上一层的x,这样由上面公式来看是正确结果,而上一层的y怎么求呢,上一层的y等于下一层的x减去a/b乘以下一层的y。而下一层的y我们已经赋值给了当前层的x,下一层的x我们已经赋值给了当前层的y,因此仔细思考,y-=(a/b)*x;就可以得到当前层的y,再一层层向上传递即可
代码之所以返回a,b的最大公因数是因为我们可能用到,这样就不需要再求一遍gcd了
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;y=0;
return a;
}
int gcd=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return gcd; //返回的是a,b的最大公因数
}
应用
1.求解二元一次不定方程
已知ax+by=c,设r=gcd(a,b),则
-
若c%r!=0,该方程组无整数解
-
若c%r==0,我们可以先求出ax+by=r对应的一组整数解,然后再乘以c并除以r即可得到ax+by=c的整数解(求的是其中的一组特殊解)
2.求逆元
若a*x在模p意义下的结果为1,那么称x为a在模p意义下的逆元,x又写作a-1记作ax ≡ 1 (mod p)
那么我们可以转化为求解ax+py=1
由于最后的求得的x可能是负数,因此我们再进行处理:(x%p+p)%p
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;y=0;
return a;
}
int gcd=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return gcd; //返回的是a,b的最大公因数
}
ll inv(ll a,ll p){
ll x,y;
exgcd(a,p,x,y);
return (x%p+p)%p;
}
3.求解线性同余方程
暂时不会,以后再补
来源:CSDN
作者:Happig丶
链接:https://blog.csdn.net/qq_44691917/article/details/104146087