以下内容为个人理解,有错误地方还请指出。
1、gcd和扩展gcd算法都要求a,b大于0;
2、ax+by=c有解的充要条件是c%gcd(a,b)==0;
3、求解ax+by=c 转换为求解a*_x+b*_y=gcd(a,b);
x=_x*c/gcd(a,b); y=_y*c/gcd(a,b);
4、如果ax+by=gcd(a,b)中b<0,则取|b|带入算法计算,
但是算出的y要加负号才是正确结果;a<0同理;
当然也可以方程两端都乘以-1;
#define LL long long
LL exgcd(LL a,LL b,LL &x,LL &y){
if(!b)
{
x=1;
y=0;
return a;
}
LL ans=exgcd(b,a%b,x,y);
LL temp=x;
x=y;
y=temp-a/b*y;
return ans;
}
LL exgcd2(LL m,LL n,LL &x,LL &y)//非递归
{
LL x1=0,y1=1,x0=1,y0=0;
LL r=(m%n+n)%n;
LL q=(m-r)/n;
x=0;y=1;
while(r)
{
x=x0-q*x1; y=y0-q*y1;
x0=x1; y0=y1;
x1=x; y1=y;
m=n; n=r; r=m%n;
q=(m-r)/n;
}
return n;
}
//poj1061
青蛙A、B分别在周长为L的圆环的x、y处,速率分别为m,n;往同一方向前进,最少多长时间A、B相遇;
//x+m*_x=y+n*_x+L*y ==> (m-n)*_x-L*_y=y-x ;
int main()//poj1061
{
LL x,y,m,n,L;
scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L);
LL _x,_y;
LL Gcd=exgcd(m-n>0?m-n:n-m,L>0?L:-L,_x,_y);
//如果m-n小于0,求出的_x要取其相反数,或者c取相反数,再计算
LL c=y-x;
if( c%Gcd || m==n)
{
printf("Impossible\n");
return 0;
}
LL num=L/Gcd;//num为_x的最大值,一般为b/gcd(a,b)
_x=m-n>0?_x:-_x;//或者c=m-n>0?c:-c;
_x=_x*c/Gcd;
_x=(_x%num+num)%num;
printf("%lld\n",_x);
}
//poj2115
周长为1<<k的环,起点为A,终点为B,每次跳跃C,最少跳多少次到达B
A+C*x=B+(1>>k)*y ==> C*x-(1<<k)*y=B-A ;
int main()//poj2115
{
LL A,B,C,k;
while (scanf("%lld%lld%lld%lld", &A, &B, &C, &k), A || B || C || k)
{
LL _x, _y;
LL Gcd = exgcd(C, (LL)1<<k, _x, _y);
if ((B - A) % Gcd )
{
printf("FOREVER\n");
continue;
}
LL num = ((LL)1<<k) / Gcd; //最大值
//最多不超过 [(1<<k)*C/(gcd(1<<k,C)] / C,
//即跳(1<<k和C的最小公倍数除以C)次后一定会回到原点;
_x = _x * (B-A) / Gcd;
_x = (_x % num + num) % num;
printf("%lld\n", _x);
}
}