POJ - 1061 青蛙约会(拓展欧几里得)

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

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/81239725