http://poj.org/problem?id=1061
题意:两只青蛙同向而行,不同速度不同位置,路径是个圆,问能不能相遇,什么时间相遇
思路:欧几里得拓展
先推公式:
L1 : x + m * t
L2 : y + n * t
L1 - L2 = K * L - - >x + m * t - y - n * t = K * L - - >t * (m - n) + (x - y) = K * L - - >K * L + t * (n - m) = y - x -->
化成A * X + B * Y = C,
A = n - m , B = L , X = t, Y = K
此时,可以用欧几里得公式
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(!b) {
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y);
ll temp = x;
x = y;
y = temp - a / b * y;
return d;
}
此时返回的d是gcd(a,b) 即x和y都代表 a * x + b * y = d 的解,那么把这个解拓展到 c就可得正确答案
我们知道 ax0 + by0 = d (<x0, y0>为一组特解)
又ax + by = c,所以 x = x0*c/d, y = y0*c/d (一定要先乘c再除以d)
好了知道ax + by = c的一组特解了,求通解还不容易?
直接安排: X = x0*c/d + kb/d, Y = y0 - ka/d
好了那么求通解有什么用呢,当然有用,例如我们求最小的x解时 观察 通解X的表达式 发现X是以 (b/d)为周期增加的,
所以我们求最小正数解是就可以 x = ((x0*c/d)%(b/d) + (b/d)) % (b/d),加一个是防止负数。
#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
using namespace std;
#define ll long long
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(!b) {
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y);
ll temp = x;
x = y;
y = temp - a / b * y;
return d;
}
int main(int argc, const char * argv[]) {
ll x, y, m, n, L;
scanf("%lld %lld %lld %lld %lld", &x, &y, &m, &n, &L);
ll a = n - m;
ll b = L;
ll t, k;
ll d = exgcd(a, b, t, k);//t, k 是 a*t + b*k = d的一组特解
ll c = x - y;//a * t + b * k = c 的通解是 t = t * c / d + u * b / d
t = ((t * c / d) % (b / d) + (b / d)) % (b / d);
t = (t + (b / d)) % (b / d);
if((x - y) % d || (m == n)) {//如果(x - y)||c不是d的整数倍,或者m速度相同
printf("Impossible\n");
}else {
printf("%lld\n", t);
}
return 0;
}