Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 62869 | Accepted: 9818 |
Description
Input
Output
Sample Input
1 2 3 4 5
Sample Output
4
对于题目中的数据,详见下表
故,可得两只青蛙跳四次就可以在点3处相遇
对于这道题可以知道,当他们相遇时距离原点的位移是相等的,则假设青蛙跳了t次后,则他们相对于原点的位移是
A:(x+mt)%l
B:(y+nt)%l
则可以列方程(x+mt)-(y+nt)=cl ( c为整数)
则变形得 (m-n)t-cl=y-x;
题目要求的就是要使等式成立时最小时的正整数t
在解决这个问题前,我们首先就应该知道什么是扩展欧几里德算法
即
找出一对整数(x,y),使得ax+by=gcd(a,b)。
注意,这里的x和y不一定是正数,也可能是负数或者0.
下面是扩展欧几里德算法的源程序:(参考刘汝佳的《算法竞赛入门经典》第179页)
1 void gcd ( int a , int b , int &d , int &x , int &y )
2 {//a,b分别代表方程的系数,d返回a,b的最大公约数,x,y返回对应的解
3 if ( ! b )//当b等于0的时候,方程就变成了ax=gcd(a,0)=a,所以此时明显可以得到方程的解为x=1,y=0,此时d就为a
4 d = a , x = 1 , y = 0 ;
5 else
6 {//递归求方程的解,等下证明
7 gcd ( b , a % b , d , y , x ) ;
8 y -= ( a / b ) * x ;
9 }
10 }
书上对该算法没有给出证明,只有“用数学归纳法并不难证明算法的正确性”一笔代过,现在,去我们就来证明该算法的正确性
当b=0时很好理解,详见上面的注释
关键是当b=/=0,则我们先来假设方程的ax+by=gcd(a,b)=d的一个正整数解为x1,y1;别怀疑,这个方程一定有解
则有ax1+by1=gcd(a,b) (1)
又对于方程bx +(a mod b)y =gcd (b ,a mod b )有解x2,y2(假设)
则有bx2+(a mod b)y2=gcd ( b,a mod b) = gcd(a, b) (2)
又a mod b = a - (a/b)*b;
则(2)式变为bx2+(a-(a/b)*b)y2=gcd(a,b);
即 ay2 + b(x2-(a/b)*y2) = gcd (a,b) (3) ;
对比(1)(3)得
x1=y2 ; y1 = x2 - (a/b)*y2
故,ax+by=gcd(a,b)的解只需要在方程bx +(a mod b)y =gcd (b ,a mod b )的解的基础上进行简单的运算就变成原来方程的解,因为gcd不断递推时会有b=0的情况出现,故可以通过递推来得到方程的解
然后得出了关于方程ax+by=gcd(a,b)的解x0,y0,
但如何要求题目所要求的解了;
假设方程是ax+by=c;
现在我们已经知道了ax+by=gcd(a,b)的解x0,y0,即ax0+by0=gcd(a,b);
则等式两边同乘以c/gcd(a,b)则得
ax0*c/gcd(a,b)+by0*c/gcd(a,b)=c;(则可知人如果c不是gcd(a,b)的倍数则无解)
故可以得到原方程的一个解是x1=x0*c/gcd(a,b),y1=y0*c/gcd(a,b),
再根据下面的结论就可以很好的得出此题的答案了
设a,b,c为任意整数。若方程ax+by=c的一组整数解为(x0,y0),则它的任意整数解都可以写成(x0+kb',y0-ka'),其中a'=a/gcd(a,b),b'=b/gcd(a,b),k为任意整数
关于上面的结论很好证明,此处略。
刚开始的时候没有注意到怎样就解答系,WA了两次
参考代码:
1 #include<iostream>
2 #include<cstdlib>
3 #include<cstdio>
4 #include<cstring>
5 #include<algorithm>
6 #include<cmath>
7 using namespace std;
8
9 void gcd ( __int64 a , __int64 b , __int64 &d , __int64 &x , __int64 &y )
10 {
11
12 if ( ! b )
13 d = a , x = 1 , y = 0 ;
14 else
15 gcd ( b , a%b , d , y , x ) , y -= x * ( a / b ) ;
16 }
17
18 int main()
19 {
20 __int64 s , t , m , n , l ;
21 while ( ~ scanf ("%I64d%I64d%I64d%I64d%I64d" , & s , & t , & m , & n , & l ) )
22 {
23 __int64 a , b , d , ans ;
24 __int64 x , y ;
25 a = l ;
26 b = m - n ;
27 ans = t - s ;
28 if ( b < 0 )
29 b = n - m , ans = s - t ;
30 gcd ( a , b , d , x , y ) ;
31 if ( ans % d )//无解出现的情况
32 printf("Impossible\n") ;
33 else
34 {
35 __int64 tmp = l / d ;
36 ans = ( ans / d * y ) % tmp ;//求出答案,因答案要求最小,故还得对答案的“周期”取余
37 if ( ans < 0 )//如果出现的是负数,就要加上周期
38 ans += tmp ;
39 printf ("%I64d\n",ans);
40 }
41 }
42 return 0;
43 }