设过s步后两青蛙相遇,则必满足以下等式:
(x+m*s)-(y+n*s)=k*l(k=0,1,2....)
稍微变一下形得:
(n-m)*s+k*l=x-y
令n-m=a,k=b,x-y=d,即
a*s+b*l=c
其实就是扩展欧几里德算法-求解不定方程 。
只要上式存在正整数解,则两青蛙能相遇,否则不能。
对原方程 a * t + b * p = d,我们要求出一组t,p;
显然c一定是gcd(a,b)的倍数,否则,两边同时除以gcd(a,b),右边会得到小数,不合法;
从而d/gcd(a,b)一定是整数;
c=gcd(a,b);
所以我们只需要通过欧几里德扩展原理求得 a * t0 + b * p0 =gcd(a,b);
得到t0,然后t0*(d/c)便是最小的解了; (因为gcd(a,b)*d/c =d)
即方程: a * t0 *(d / c) + b * p0 * (d / c) = d; 但是t0可能是负数
我们做一点变换得到
a * ( t0 *(d / c) + b*n) + b * (p0 * (d / c) – a*n) = d; (n是自然数) (+a*b*n-a*b*n)
b * x0 + (a % b) * y0 = gcd( b, a % b); (2)
联立两式,
a * x + b * y = b * x0 + (a % b) * y0
= b * x0 + (a – a / b * b) * y0
= a * y0 + ( x0 – a / b * y0 ) * b
所以得到 x = y0, y = x0 – a / b * y0;
而y0,x0就又得通过y1,x1来求得,也就是像求gcd一样,一直递归下去 ,直到最后a%b==0,
此时 的x0=1;y=0; (相当于情况1)
以下是求扩展欧几里德的程序
void extend_euild(__int64 a, __int64 b)
{
if (b==0)
{
t=1;
p=0;
}
else
{
extend_euild(b,a%b);
__int64 tmp=t;
t=p;
p=tmp-a/b*p;
}
}
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
__int64 gcdc(__int64 a,__int64 b){
if(b==0)
return a;
return gcdc(b,a%b);
}
__int64 t,p,c;
void extend_euild(__int64 a, __int64 b)
{
if (b==0)
{
t=1;
p=0;
}
else
{
extend_euild(b,a%b);
__int64 tmp=t;
t=p;
p=tmp-a/b*p;
}
}
int main()
{
__int64 x,y,n,m,l;
scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&l);
if (m==n){
cout<<"Impossible"<<endl;
return 0;
}
__int64 a=n-m;
__int64 b=l;
__int64 d=x-y;
__int64 gcd=gcdc(a,b);
if (d%gcd)
{
printf("Impossible\n");
return 0;
}
extend_euild( a, b );
t*= d/gcd ;
while( t< 0 )
{
t+= b;
}
printf( "%I64d\n", t%b );
return 0;
}