传送门:POJ 1061 - 青蛙的约会

题目大意:
在同一条纬度线上,青蛙 A, B 分别以 $x,y$ 为起点向西跳,A 青蛙每次能跳 $m$ 米,B 青蛙每次能跳 $n$ 米,两个青蛙跳一次时间相同,纬度线总长为 $L$ ,问跳多少次以后两青蛙相遇,如果始终不能相遇输出 “Impossible”。

解题思路:
因为都朝西跳,所以如果有可能相遇,那么相遇时两只青蛙总路程 “A 青蛙的跳跃距离加上 A 青蛙起点” 与 “B 青蛙的跳跃距离加上 B 青蛙的起点” 的差值一定是纬度线总长 $L$ 的整数倍数。设相遇时跳跃次数为 $t$,相遇时总路程差值是 $L$ 的 $c$ 倍($c\in Z$,不过这个 $c$ 并不重要),可得 $(mt+x)-(nt+y)=Lc$,化为我们需要的形式得 $(m-n)t-Lc=y-x$ ($t,c$ 为未知数),可以看出这个式子是二元一次方程,所以可以使用扩展欧几里得算法求解,然后将 $t$ 化为最小正整数解即可。又因为该算法只能求得整数解,所以如果无解,就说明两个青蛙始终无法相遇。注意题目数据范围较大,数据类型使用 long long。

通过代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
long long exgcd(long long a, long long b, long long &x, long long &y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
long long q = exgcd(b, a % b, y, x);
y -= a / b * x;
return q;
}
bool eqa_solve(long long &x, long long &y, long long &g, long long a, long long b, long long c)
{
g = exgcd(a, b, x, y);
if (c % g != 0)
return false;
long long tms = c / g;
x *= tms;
y *= tms;
return true;
}
int main(void)
{
long long x, y, m, n, L;
long long t, c, gcd;
scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &L);
if (eqa_solve(t, c, gcd, m - n, L, y - x))
{
long long mod = L / gcd;
printf("%lld\n", (t % L + L) % L); // 将 t 化为最小正整数解并输出
}
else
printf("Impossible\n");
return 0;
}