题目 | 青蛙的约会
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$ 个整数 $x$,$y$,$m$,$n$,$L$,其中 $x\neq y<2\cdot10^9$,$0<m,n<2\cdot10^9$,$0<L<2.1\cdot10^9$。
Output
输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行 "Impossible".
Sample Input
1 2 3 4 5
Sample Output
4
题解
扩展欧几里得算法基础题,扩欧算法笔记:https://io.zouht.com/67.html
在 $t$ 时刻时 ($t\in\mathbb{Z}$),$A$ 的位置为 $x+t\cdot m$,$B$ 的位置为 $y+t\cdot n$
若此时 $A$ 与 $B$ 相遇,则满足:
$$ (y+t\cdot n)+k\cdot L=(x+t\cdot m)\;(其中t,k\in\mathbb{Z}) $$
变形可得到:
$$ t\cdot(n-m)+k\cdot L=x-y\;(其中t,k\in\mathbb{Z}) $$
不妨令 $a=n-m,b=L,c=x-y,d=\gcd(a,b)$,式子可化为:
$$ a\cdot t+b\cdot k=c\tag{*} $$
可发现这是一个关于未知数 $t$ 和 $k$ 的线性丢番图方程,当 $d\mid c$ 时有整数解,可通过扩欧算法得到:
$$ a\cdot t'+b\cdot k'=d $$
的解 $t',k'$,从而得到原方程 $(*)$ 的解:
$$ \begin{cases} t_0=t'\cdot(c/d)\\ k_0=k'\cdot(c/d)\\ \end{cases} $$
上面得到的为特解 $t_0$,我们要求的为最小正数。通过通解公式:
$$ \begin{cases} t=t_0-p\cdot(b/d)\\ k=k_0+p\cdot(a/d)\\ \end{cases} $$
我们可以找到最小正数解 $t$ 为:
$$ t=[t_0\bmod (b/d)+(b/d)]\bmod(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;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi