1. 程式人生 > >擴充套件歐幾里得演算法——exgcd

擴充套件歐幾里得演算法——exgcd

擴充套件歐幾里德演算法是用來在已知a,ba,b求解一組x,yx,y,使它們滿足貝祖(裴蜀)等式: ax+by=gcd(a,b)=dax+by = gcd(a, b) =d

試著來搞一下

ax+by=gcd(a,b)ax+by=gcd(a,b)

先考慮一下特殊情況,如果b=0b=0,那麼gcd(a,b)=agcd(a,b)=a,顯然存在一組解x=1,y=0x=1,y=0

設當前的式子為ax1+by1=gcd(a,b)ax_1+by_1=gcd(a,b),肯定存在式子b

x2+(abx_2+(a%b)y2=gcd(b,ab)y_2=gcd(b,a%b)b)

根據歐幾里得演算法,gcd(a,b)=gcd(b,agcd(a,b)=gcd(b,a%b)b)

ax1+by1=bx2+(a\therefore ax_1+by_1=bx_2+(a%b)y2b)y_2

a\because a%b=aa/bbb=a-a/b*b(這裡的除是指整除)

ax1+by1=bx2+(aa/bb)y2\therefore ax_1+by_1=bx_2+(a-a/b*b)y_2


    ax1+by1=bx2+ay2a/bby2ax_1+by_1=bx_2+ay_2-a/b*b*y_2
    ax1+by1=ay2+b(x2a/by2)ax_1+by_1=ay_2+b(x_2-a/b*y_2)

x1=y2,y1=x2a/by2\therefore x_1=y_2,y1=x_2-a/b*y2

於是就可以愉快的遞推下去了

程式碼賊短:

int exgcd(int
a,int b,long long &x,long long &y) { if(b==0)return x=1,y=0,a; int d=exgcd(b,a%b,y,x); return y-=a/b*x,d; }

順便普及一下逗號運算子,:在c++中,(a,b,c)==c。(巧妙的使用可以使得程式碼複雜度降低)

當然exgcd不可能只有這麼點用途呀,它還可以用來求逆元,並且比用費馬小定理求更方便,比如求aa在模pp意義下的逆元,如果用費馬小定理求的話,還要保證pp是個質數,但是用exgcd就不用了。

怎麼求呢?

xxaa在模pp意義下的逆元,那麼滿足式子:
ax1ax \equiv 1 (mod(mod m)m)

那麼有:

ax+my=1ax+my=1

然後用exgcd搞出aa即可(以及這就是為什麼 a和m一定要互質 才能使得aa在模mm意義下有逆元)

以及逆元的程式碼在此:

long long inv(long long a,long long m)
{
    long long x,y;
    long long d=exgcd(a,m,x,y);
    return d==1?(x+m)%n:-1;//不互質就沒有逆元
}