欧几里德
int gcd(int a,int b){
if(b) while(b^=a^=b^=a%=b);
return a;
}
扩展欧几里德
int ext_gcd(int a,int b,int &x,int &y){
if(b==0){
x=1;
y=0;
return a;
}
int ans=ext_gcd(b,a%b,y,x);
y-=(a/b)*x; // x=y` y=x`-[a/b]*y`
return ans;
}
求得ax+by=gcd
若x+=k*(b/gcd) y-=k*(a/gcd),等式一样成立
二进制gcd算法:
如果a和b都是偶数,则gcd(a,b)=2*gcd(a/2,b/2)
如果a是奇数,b是偶数,则gcd(a,b)=gcd(a,b/2)
如果a和b都是奇数,则gcd=(b,(a-b)/2)
例题: HDOJ 1576
题目:
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
做法:
根据题目我们知道: n=A%9973=A-A/9973*9973。设A/B=x,则A=Bx。所以Bx-A/9973*9973=n。
即
Bx-9973y=n ---① (y是多少不重要也不用管 ,用不上)
题目所求的值就是x%9973的值
利用扩展欧几里德算法可求出gcd(B,9973)=Bx1+9973y1=1 的x1,x=n*x1(等式两边乘于n就是①式了嘛)
为什么可以这样做:①式有无数解,最原始的解就是x0 = x1* n/ gcd(B,9973)
其他解可
通过x=x0+t*9973, y=y0-t*B(t为整数)得来!!
得到的x可能为负值,所以还需要x=(x%9973+9973)%9973。(x=abs(x)%9973是错的)
怕不同编译器对余数的符号取法不一样出错,就用
if(x<0) x=x+(-x/9973+1)*9973;
else x=x%9973;