这里展开简单叙述,但不证明:
由欧几里得算法:
gcd(a,b)=gcd(b,a%b)
假设ax+by=gcd的解为 x1,y1。
由欧几里得+裴蜀定理我们不难得到另一种构造: bx2+(a%b)y2=gcd
这两个等式都等于c
也就是说我们有这样的等式:
ax1+by1 = bx2+(a%b)y2
将a%b展开得到:
ax1+by1= bx2+ (a-[a/b]*b)y2 = bx2+ay2-b*[a/b]*y2 = ay2+ b(x2-[a/b]*y2)
由恒等式定理:恒等式左边a的系数必然等于恒等式右边的a的系数
x1=y2
y1=x2-[a/b]*y2
由于我们已经知道a,b的值,倘若我们知道x2,y2的值,我们必然能够求解出x1,y1;
但是我们如何求解x2,y2呢,我们可以将 对其再用欧几里得+裴蜀定理进行构造。
也就是换元+重复上面的步骤,所以我们用递归解决。
然而递归的边界是什么呢?
我们不断进行 a=b,b=a%b的操作,最终b必然会为0,也就是 ax +0*y=gcd(a,b)
即原式最终可以推到成这个ax +0*y=gcd(a,b),或者也可以说从这个式子推导出原式。
那么此时 x=1,y=任何数,这里取0
所以我们就可以用 x=1,y=0 递归过去。
下面是代码实现:
void exgcd(int a,int b,int &x ,int &y){
if(b==0){
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
//不断递归,直到最次底层,由于每一层的x是上一层的y,每一层的y代表上一层的x,所以次底层的
//x1=0,y1=1,而次底层的x1为上底层的y2,次底层的y1为上一层的x2。即
//即x1=y2,y1=x2-a/b*y2
//所以:
y-=a/b*x
void exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return ;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
}
由于此处的x,y是 ax+by=gcd的解,若要求ax+by=c的解,那么我们就直接给x,y乘 c/gcd 即可
然后我们利用拓展欧几里得算法求出了ax+by=c的一个解,
我们怎么求出所有的解?
只需要再次求出 ax+by=0的最小整数解即可。
(此处证明略)
a和b的最小公倍数lcm(a,b)
也就是ax=lcm(a,b) , by=-lcm(a,b)
即 : x= lcm(a,b)/a , y= -lcm(a,b)/b
下面是关于P1516的题解:
x+mt == y+nt (mod L)
当他们同一时间,跳到同一点上:
假设这个数轴长L 米,经过t秒后青蛙A应该在的坐标为: (x+mt)mod L
青蛙B应该在的坐标为: (y+nt)mod L要使得最终能相遇,应该是在同一时间他俩的坐标相同,
也就是 x+mt 与 y+nt 同余 ,t有解整数解,求t的最小正整数解。
假如青蛙A 领先青蛙B z圈,也就是青蛙A领先青蛙B,
zL米则有: x+mt + z*L = y+nt
(m-n)*t +L*z =y-x
也就是求,t,z的二元一次方程的解
由拓展欧几里得算法,
ax+by=gcd(a,b)
先判断 y-x是不是 gcd((m-n),L)的倍数
若不是,则直接输出不可能,结束函数。若是,那么t,z一定有解,用拓展欧几里得求出他们的解
t1,z1.
注意,此时t1,z1的解是 :(m-n)*t +L*z =gcd(m-n,L)
的解,因为我们要求的是:(m-n)*t +L*z =y-x,所以我们乘相应的倍数即可
所以真正的解 t1= t1* (y-x)/gcd(m-n,L)
然后再求出(m-n)*t +L*z =0 的最小整数解
解出 t2=L/gcd(m-n,L),z2=-(m-n)/gcd(m-n,L)
假设gcd(m-n,L)=d
然后就可以得到所有的解:
t=t1+k*L/d;
然后如果当前得到的解,小于0,只要不断的加上L/d,直到其大于0即可若得到的解大于零,只要mod L/d 就可得到最小正整数解
上代码:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include