一年前刷的题,然而一年没刷数学了。。。。。。
题意:
A开始在p点,每次可以前进m,B开始在q点,每次可以前进n,坐标轴是一个长度为L的环,问A前进多少次后可以遇到B
思路:
设一个可行的前进次数为x,那么可以列出方程:
(p+x*m)%L = (q+x*n)%L
转化一下:
(x*(m-n))%L = (q - p)%L
设(x*(m-n))与(q-p)之间相差y个L
则:
(x*(m-n)) + y * L = q - p;
这里注意一下如果m-n是负数的话要换成n-m,相应的q-p换成p-q(只保证m-n非负就可以,不用保证q-p非负)
设a=(m-n), b = L, c = q - p;
那么(x*(m-n)) + y * L = q - p就变成了a*x + b*y = c
根据扩展欧几里得定理我们可以求得a*xx + b * yy = gcd(a, b)的解xx,那么x=xx*c/gcd(a, b)
但这只是x的任一解,题目中要求的是求x的最小正整数解
我们先把a*xx + b * yy = gcd(a, b)求出的解(xx,yy)带入a*x + b*y = c得:
(a*c/gcd(a,b))*x+(b*c/gcd(a,b))*y = c
那么x每减少tx,y就要增加ty,保证(a*c/gcd(a,b))*tx=(b*c/gcd(a,b))*ty,移项得tx/ty = (b/gcd(a, b)) / (a/gcd(a, b))
我们可以推断出要想让x最小,就要尽可能多的去除tx,也就是尽可能多的去除(b/gcd(a,b)), 答案就是x%(b/gcd(a, b))
考虑到x一开始就是负数的情况,把式子转化一下:(x%(b/gcd(a, b))+(b/gcd(a, b))) % (b/gcd(a, b)),就是最终答案了
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; ll exgcd(ll a, ll b, ll& x, ll& y) { if (b == 0) { x = 1, y = 0; return a; } ll r = exgcd(b, a % b, y, x); y -= a / b * x; return r; } int main() { ll p, q, m, n, L; while (~scanf("%lld%lld%lld%lld%lld", &p,&q,&m,&n,&L)) { ll a = m - n, b = L, c = q - p, x, y; if (a < 0) a = -a, c = -c; ll d = exgcd(a, b, x, y); if (c % d) { printf("Impossible\n"); continue; } x *= c / d; ll t = b / d; printf("%lld\n", (x % t + t) % t); } return 0; }