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 }