P1516 青蛙的约会
题意:在一个长为\(l\)的环上面有两只青蛙,一只出发点为\(x\),一次跳\(m\),另一只出发点为\(y\),一次跳\(n\),求相遇时间。
这个长为\(l\)的环不难想到了以\(l\)为模的同余。其实就是求这个\(t\):\(x+t\times m \equiv y + t \times n\pmod l\)
把这个变成普通式子:\(x - y + t(m - n) = k \times l\)
整理一下:\(t \times (m-n) - k \times l = y - x\)
这是一个二元不定方程,也就很自然地想到了另一个式子:\(t' \times (m-n) - k' \times l = gcd(m - n, l)\)
用肥鼠定理可以判断无解。套exgcd模板可以求出\(t'\)和\(k'\)。
上面两个式子如果有解的话一定是倍数关系的,所以有这么一个式子:\(\frac{gcd(m-n,l)}{y-x} = \frac{t'}{t}\),即\(t=\frac{t'(y-x)}{gcd(m-n,l)}\)。
但是\(t\)可能是负数,我们需要调整\(t\)为最小正整数解。
使用exgcd的通解公式:\(x=x_0+k\times \frac{b}{gcd(a,b)}\)。把里面的式子换成这道题的就行了。
有个需要注意的:
\(gcd\)是不支持负数的,所以这个\(y-x\)要确保为正,当这个\(y-x\)为负时,同时给\(m-n\)和\(y-x\)添负号。
代码:
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
#define ll long long
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) {
x = 1; y = 0; return a;
} else {
ll ret = exgcd(b, a % b, x, y);
ll t = x;
x = y;
y = t - a / b * y;
return ret;
}
}
int main() {
ll x, y, m, n, l; cin >> x >> y >> m >> n >> l;
// x + m * t === y + n * t (mod l)
// x - y + t * (m - n) = k * l
// t * (m - n) - k * l = y - x
ll A = m - n, B = l, C = y - x;
if(A < 0) {
A = -A; C = -C;
}
ll g = exgcd(A, B, x, y);
if(C % g) {
cout << "Impossible" << endl;
return 0;
}
x = x * C / g;
// C : g = t : x
ll bg = B / g;
if(bg < 0) bg = -bg;
x = (x % bg + bg) % bg;
cout << x << endl;
return 0;
}