输入两个数a,b
求x,y满足
a*x+b*y=gcd(a,b)
比如说输入3,5
解出来x=2,y=-1
所以说,怎么解?
我们假设已经求出x1,y1使
b*x1+(a%b)*y1=gcd(b,a%b)
成立
那么x1与x,y1与y的关系是什么呢
因为
gcd(a,b)=gcd(b,a%b)
所以
a*x+b*y==b*x1+(a%b)*y1
即([]为取整)
a*x+b*y==b*x1+(a-b*[a/b])*y1
右边展开再分配
a*x+b*y==a*y1+b*(x1-[a/b]*y1)
发现
x==y1 , y==x1-[a/b]*y1时成立
于是我们就能递归,边界?
当b==0时,gcd(a,b)=a,x=1,y=0
举个例子
求x,y满足5*x+3*y==1
我们递归下去,发现要求出这个x1,y1
3*x1+2*y1==1
继续,要求x1,y1就要求x2,y2
2*x2+1*y2==1
继续,要求x2,y2就要求x3,y3
1*x3+0*y3==1
遇到边界,即b==0,都搞定了
1.a==1,b==0
x3 = 1 , y3 = 0 -> 1*1+0*0=1
2.a==2,b==1
x2 = y3 = 0 , y2 = x3 - [a/b] * y3 = 1 - [2/1] * 0 = 1 -> 0*2+1*1=1
3.a==3,b==2
x1 = y2 = 1 , y1 = x2 - [a/b] * y2 = 0 - [3/2] * 1 = -1 -> 1*3+(-1)*2=1
4.a==5,b==3
x = y1 = -1 , y = x1 - [a/b]*y1 = 1 - [5/3] * (-1) = 2 -> (-1)*5+(2)*3=1
是不是觉得特别巧妙
实在不理解先背代码
void exgcd(int a,int b)
{
if(b==0) g=a,x=1,y=0;
else{
exgcd(b,a%b);
int x1=y,y1=x-a/b*y;
x=x1,y=y1;
printf("%d*(%d)+%d*(%d)=%d\n",a,x,b,y,g);
}
}
输出来是
并且
int tmp=gcd(a,b)
若a*x+b*y=tmp成立
a*(x+b/tmp)+b*(y-a/tmp)=tmp成立
即 5*2+3*(-3)=1 , 5*5+3*(-8)=1 ...
应用
同余方程(NOIP2012提高组)
a*x=b*k+1
a*x-k*b=1 , 令y=-k
a*x+b*y=1
找出一组最小正整数解即可
若x<0 x+=b
青蛙的约会
设跳了k步
(x+m*k)%L==(y+n*k)%L
(x+m*k)-(y+n*k)=L*q(q为整数)
k*(m-n)-L*q=y-x
设a=k , x=m-n , b=-L , y=q , tmp=y-x
a*x+b*y=tmp
若tmp!=gcd(a,b) 无解
答案为最小正整数解