扩展欧几里德算法证明及求逆元【转】

扩展欧几里德以及证明

定理
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在无数组整
数对 x,y ,使得 gcd(a,b)=ax+by。
证明
求解 x,y的方法的理解
设 a>b。
1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2,a>b>0 时
设 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
则:ax1+ by1= bx2+ (a mod b)y2;
即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
根据恒等定理得:x1=y2; y1=x2- [a / b] *y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
应用
如果ax+ by= c;求解不定方程非负整数方案数;
代码如下
pascal

  function gcd(a,b:int64):int64;
  var c:int64;
  begin
        c:=a mod b;
        while c<>0 do
        begin
                a:=b;b:=c;c:=a mod b;
        end;
        exit(b);
  end;
  procedure exgcd(a,b:int64;var x,y:int64);
  var q,r:int64;
  begin
        if b=0 then
        begin
                x:=1;y:=0;exit;
        end;
        q:=a div b;r:=a mod b;
        exgcd(b,r,y,x);
        y:=y-q*x;
  end;
  function fm(x,y,mo:int64):int64;
  var s:int64;
  begin
        if x<0 then
        begin
                x:=x*-1;y:=y*-1;
        end;
        s:=0;
        while x<>0 do
        begin
                if x mod 2=1 then s:=(s+y) mod mo;
                y:=y shl 1 mod mo;
                x:=x shr 1;
        end;
        exit(s);
  end;
  procedure init;
  begin
        readln(a,b,c);
        g:=gcd(a,b);
        if c mod g<>0 then
        begin
                writeln(0);
                continue;
        end;
        a:=a div g;b:=b div g;c:=c div g;
        exgcd(a,b,x,y);
        x:=fm(x,c,b);y:=fm(y,c,a);
        x:=(x mod b+b) mod b;
        y:=(y mod a+a) mod a;
        tx:=(c-b*y) div a;
        writeln((tx-x)div b+1);
  end;

c++

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a,b,c,x,y;
int t;
ll fm(ll x,ll y,ll mod){
    if(x<0) x*=-1ll,y*=-1ll;
    ll s=0;
    while(x){
        if(x&1) s=(s+y)%mod;
        y=(y+y)%mod;x>>=1ll;
    }
    return s;
}
ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}
void exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1;y=0;return;
    }
    ll q=a/b,r=a%b;
    exgcd(b,r,y,x);
    y-=q*x;
}
int main(){
    ios::sync_with_stdio(0);
        cin>>a>>b>>c;
        ll g=gcd(a,b);
        if(c%g){
            cout<<0<<'\n';continue;
        }
        a/=g;b/=g;c/=g;
        exgcd(a,b,x,y);
        x=fm(x,c,b);y=fm(y,c,a);
        x=(x%b+b)%b;
        y=(y%a+a)%a;
        ll tx=(c-b*y)/a;
        cout<<(tx-x)/b+1<<'\n';
    return 0;
}

逆元

定理
设x是a的逆元,则有a*x≡1(mod m);
扩欧求逆元
已知ax+by≡gcd(a,b),求a模b的逆元
利用解ax+by=c的方法求逆元(即当c=1时)
代码(转):

ll extend_gcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    else {
        ll r = extend_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return r;
    }
}
ll inv(ll a, ll n) {
    ll x, y;
    extend_gcd(a, n, x, y);
    x = (x % n + n) % n;
    return x;
}

【第一次写博客写的不好请多多指教^_^】

猜你喜欢

转载自blog.csdn.net/czx1232004/article/details/81636937