题意
有两只青蛙在圆环上,圆的周长为LLL,出生点分别为xxx,yyy。第一只青蛙每次可以跳mmm距离远,第二只青蛙每次可以跳nnn距离远,现在问你如果两只青蛙同时一直往一个方向跳,是否能过碰面。能的话输出跳的次数,不能碰面就输出“Impossible”
分析
首先我们列几个式子分析一下,假设他们跳了ttt次且都往右边跳,那么对于第一只青蛙AAA有如下等式 la=mt+xl_a=mt+xla=mt+x,对于第二只青蛙 BBB 有 lb=nt+yl_b=nt+ylb=nt+y。最后他们要碰面,而他们在圆环上,则肯定满足 la=lb+kLl_a = l_b+kLla=lb+kL。将上面的式子代入我们可以得到mt+x=nt+y+kLmt+x=nt+y+kLmt+x=nt+y+kL。化简可以得到t(m−n)−kL=y−xt(m-n)-kL=y-xt(m−n)−kL=y−x。其中m−n,L,y−xm-n,L,y-xm−n,L,y−x都是已知的。那么我们很容易联想到扩展欧几里得ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b),可以解出x,yx,yx,y的一个特解。
这里我们先暂停一下,紫书上面对于扩展欧几里得有两个结论
-
设a,b,ca,b,ca,b,c为任意整数,若方程ax+by=cax+by=cax+by=c的一组整数解为(x0,y0)(x_0,y_0)(x0,y0),则它的任意整数解都可以写成(x0+kb′,y0+ka′)(x_0+kb',y_0+ka')(x0+kb′,y0+ka′),其中a′=a/gcd(a,b),b′=b/gcd(a,b)a'=a/gcd(a,b),b'=b/gcd(a,b)a′=a/gcd(a,b),b′=b/gcd(a,b)
-
设 a,b,ca,b,ca,b,c 为任意整数,g=gcd(a,b)g = gcd(a,b)g=gcd(a,b),方程ax+by=gax+by=gax+by=g的一组解是(x0,y0)(x_0,y_0)(x0,y0),则当ccc是ggg的倍数时ax+by=cax+by=cax+by=c的一组解是(x0cg,y0cg)(\frac {x_0c}{g},\frac {y_0c}{g})(gx0c,gy0c)。当ccc不是ggg的倍数时无整数解
我们要求的是ttt的最小值,由第二条性质我们可以知道,当(y−x)(y-x)(y−x)是gcd(m−n,L)gcd(m-n,L)gcd(m−n,L)的倍数时,才有解,否则他们不可能相遇。由第一条性质我们可以不断的减去L/gcd(L,m−n)L/gcd(L,m-n)L/gcd(L,m−n)得到ttt的最小值
但是我看有的题解是直接用的b好像也可以,感觉是不是数据很弱 有哪里我没弄明白的?然后还有个问题就是负数。我看网上好多代码都是只保证了是ax+by=cax+by=cax+by=c前面的aaa是正数,在本题中就是保证m−nm-nm−n是正数,这种情况下ccc就是y−xy-xy−x,否则就是n−mn-mn−m和x−yx-yx−y。但是如果这样的话上面方程的ccc是负数怎么办,看起来好像不影响结果。
还有一点就是得到了t的一个通解以后,如何求恰好大于0的那个解。如果ttt是正数,那么直接模掉就行了,如果是负数那么就要先求模,然后加上模在求模。这个就涉及到了负数求模。在c++/java中余数 = 被除数 - (被除数/除数)* 除数。也就是说负数取模可以理解成不带负号取模,然后再把负号加上去??看起来好像是这样吧。。。
还有就是紫书上的两个性质,这个可以自己下去推一推,也比较好推。不想推的记住好像也可以? 数论的题做起来真难受。
代码
#include <iostream>
using namespace std;
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (a == 0 && b == 0) return -1;
if (b == 0) { 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;
while (cin >> x >> y >> m >> n >> L)
{
ll a = m - n;
ll b = L;
ll c = y - x;
ll xx, yy;
if (a < 0)
{
a = -a;
c = -c;
}
ll gcd = exgcd(a, b, xx, yy);
if (c%gcd) cout << "Impossible" << endl;
else
{
xx = xx * c / gcd;
ll bb = b/gcd;
xx = (xx%bb + bb) % bb;
cout << xx << endl;
}
}
return 0;
}