扩展欧几里德首先要提到的是裴蜀定理:
设 gcd(a,b)=c,则对于任意实数 x,y 有 c|ax+by 成立
特别的,一定存在 x,y 满足 ax+by=c
推论:a,b 互质等价于 ax+by=1 有解。
求解 x,y:
设 a>b。
(1) 当 a mod b =0 时,gcd(a,b)=b。此时 x=0,y=1。
因为 0*a+1*b=b
(2) 当 a mod b!=0 时
设 ax1+by1=gcd(a,b),bx2+(a mod b)y2=gcd(b,a mod b);
据欧几里德原理有:ax1+by1=bx2+(a mod b)y2;
因为 a mod b=a-(a/b)*b;
则有:ax1+by1=bx2+(a-a(a/b)*b)y2
根据恒等原理有: x1=y2,y1=x2-(a/b)*y2;
于是我们便有了代码:
1 #include <cstdio> 2 using namespace std; 3 long long a,b,x,y; 4 5 void exgcd(long long a,long long b,long long &x,long long &y) 6 { 7 if(a%b==0) 8 { 9 x=0;y=1;return ; 10 } 11 exgcd(b,a%b,x,y); 12 long long t=x; 13 x=y;y=t-(a/b)*y; 14 } 15 16 int main() 17 { 18 scanf("%lld%lld",&a,&b); 19 exgcd(a,b,x,y); 20 printf("%lld%lld",x,y); 21 return 0; 22 }
其实,这个代码还有个压缩版本:
1 #include <cstdio> 2 using namespace std; 3 long long a,b,x,y; 4 5 void exgcd(long long a,long long b,long long &x,long long &y) 6 { 7 if(a%b==0) 8 { 9 x=0;y=1;return ; 10 } 11 exgcd(b,a%b,y,x); //注意了, y 在前, x 在后 12 y-=x*(a/b); 13 } 14 15 int main() 16 { 17 scanf("%lld%lld",&a,&b); 18 exgcd(a,b,x,y); 19 printf("%lld%lld",x,y); 20 return 0; 21 }
扩展欧几里德可以用来解二元一次不定方程
例如:不定方程ax+by=d
设 c=gcd(a,b);
先用扩欧解出 ax+by=c 的解 x0,y0
x0=x0*d/c; y0=y0*d/c。
x,y的通解为
x=x0+b/c*t;
y=y0+a/c*t;
不定方程 ax+by=d 有整数解的条件:
d mod gcd(a,b)==0
求解 x 的最小非负整数解:
1 #include <cstdio> 2 using namespace std; 3 long long a,b,c,d,x0,y0,x; 4 5 long long gcd(long long x,long long y) 6 { 7 return (x%y==0)?y:gcd(y,x%y); 8 } 9 10 void exgcd(long long a,long long b,long long &x,long long &y) 11 { 12 if(a%b==0) 13 { 14 x=0;y=1;return ; 15 } 16 exgcd(b,a%b,y,x); 17 y-=x*(a/b); 18 } 19 20 int main() 21 { 22 scanf("%lld%lld%lld",&a,&b,&d); 23 c=gcd(a,b); 24 if(d%c) 25 { 26 puts("No solution.");return 0; 27 } 28 a/=c;b/=c;d/=c; 29 exgcd(a,b,x0,y0); 30 x=x0%b; 31 while(x<0)x+=b; 32 printf("%lld",x); 33 return 0; 34 }
例题:poj 1061 青蛙的约会