POJ1061. 青蛙的约会

http://poj.org/problem?id=1061

1000MS / 10000K

Description

两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。

我们把这两只青蛙分别叫做青蛙 A 和青蛙 B ,并且规定纬度线上东经 0 度处为原点,由东往西为正方向,单位长度 1 米,这样我们就得到了一条首尾相接的数轴。设青蛙 A 的出发点坐标是 x,青蛙 B 的出发点坐标是 y。青蛙 A 一次能跳 m 米,青蛙 B 一次能跳 n 米,两只青蛙跳一次所花费的时间相同。纬度线总长 L 米。现在要你求出它们跳了几次以后才会碰面。

Input

输入只包括一行 5 个整数 xymnL,其中 xy<21090<m,n<21090<L<2.1109

Output

输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行 "Impossible".

Sample Input

1 2 3 4 5

Sample Output

4

题解

扩展欧几里得算法基础题,扩欧算法笔记:https://io.zouht.com/67.html

t 时刻时 (tZ),A 的位置为 x+tmB 的位置为 y+tn

若此时 AB 相遇,则满足:

(y+tn)+kL=(x+tm)(t,kZ)

变形可得到:

t(nm)+kL=xy(t,kZ)

不妨令 a=nm,b=L,c=xy,d=gcd(a,b),式子可化为:

(*)at+bk=c

可发现这是一个关于未知数 tk 的线性丢番图方程,当 dc 时有整数解,可通过扩欧算法得到:

at+bk=d

的解 t,k,从而得到原方程 () 的解:

{t0=t(c/d)k0=k(c/d)

上面得到的为特解 t0,我们要求的为最小正数。通过通解公式:

{t=t0p(b/d)k=k0+p(a/d)

我们可以找到最小正数解 t 为:

t=[t0mod(b/d)+(b/d)]mod(b/d)

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
    {
        x = 1;
        y = 0;
        return a;
    };
    ll d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main()
{
    ll x, y, m, n, L;
    cin >> x >> y >> m >> n >> L;
    ll a = n - m, b = L, c = x - y;
    if (a < 0)
    {
        a = -a;
        c = -c;
    }
    ll p, q;
    ll d = exgcd(a, b, p, q);
    if (c % d)
        cout << "Impossible" << endl;
    else
        cout << (p * (c / d) % (b / d) + (b / d)) % (b / d) << endl;
    return 0;
}