青蛙的约会
有两只青蛙,青蛙A和青蛙B,它们在一个首尾相接的数轴上。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。数轴总长L米。要求它们至少跳了几次以后才会碰面。
根据题意 可有方程 ( x + m * t ) % L = ( y + n * t ) % L
即 x + m * t = y + n * t + k * L (k 是整数)
化简有 ( m - n ) * t + k * L = y - x 即 ax + by = c 类型
扩展欧几里得:是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b)(解一定存在,根据数论中的相关定理)。
所以我们可求得 ( m - n ) * t + k * L = gcd(m - n,L) 这个等式的一组解。由上述简介可知,当 ( y - x ) % gcd(m - n,L) != 0 时,原方程无解。
到这一步就是方程有解的情况:
首先引入两个定理:
定理一:若gcd(a, b) = 1,则方程ax ≡ c (mod b)在[0, b-1]上有唯一解。
定理二:若gcd(a, b) = d,则方程ax ≡ c (mod b)在[0, b/d - 1]上有唯一解。
对方程,设 a = ( m - n ) , b = L , c = gcd(a,b) ,则有 a * t + b * k = c,且设此方程的一组特解为
那么 ( m - n ) * t + k * L = y - x 有 ,显然 ,且此方程有一组特解
由定理二,方程 的最小正数解在 上。( 其实和 a * t + b * k = c 一样 )
所以 t 最后的最小正数解即为 ,由于原本可能为负,所以 mod 之后还需要 + (b / c) 再 mod (b / c)
贴上代码:
#include<iostream>
#include<cstdio>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define INT(t) int t; scanf("%d",&t)
using namespace std;
LL exgcd(LL a,LL b,LL &x,LL &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
LL r = exgcd(b,a % b,x,y);
LL tmp = x;
x = y;
y = tmp - a / b * y;
return r;
}
int main() {
LL x,y,m,n,l;
while(~scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l)){
if(m < n){
swap(m,n);
swap(x,y);
}
LL t,k;
LL a = m - n,b = l;
LL c = exgcd(a,b,t,k);
LL tmp = ((y - x) % l + l) % l;
if(tmp % c != 0){
printf("Impossible\n");
}
else {
b = b / c;
tmp = tmp / c;
t = tmp * t;
cout << (t % b + b) % l << endl;
}
}
return 0;
}