扩展欧几里德以及证明
定理:
对于不完全为 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;
}