扩展欧几里德

来源:互联网 发布:淘宝手机端发布详情页 编辑:程序博客网 时间:2024/06/03 20:55
欧几里德

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;
1 0
原创粉丝点击