设过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; }