[POJ 1061]--青蛙的约会(扩展欧几里得)

                                                               青蛙的约会

Time Limit: 1000MS
Memory Limit: 10000K

 


题目链接:http://poj.org/problem?id=1061

 

Description

两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是 它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下 去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只 青蛙是否能够碰面,会在什么时候碰面。 
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设 青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你 求出它们跳了几次以后才会碰面。 

Input

输入只包括一行5个整数x,y,m,n,L,其中x≠y < 20
00000000,0 < m、n < 2000000000,0 < L < 2100000000。

Output

输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"

Sample Input

1 2 3 4 5

Sample Output

4

 

解题思路:首先把这道题转化为相关的数学方程:(n-m)t+pL=x-y,即二元一次不定方程at+bp=c,根据数论的相关定理,得知当c%gcd(a,b)==0时方程有整数解,

     否则没有,即此题无解。

引用以下定理:

定理1 gcd(a,b)是ax+by的线性组合的最小正整数,x,y∈z;
定理2 如果ax+by=c,x,y∈z;则c%gcd==0;
定理3 如果a,b是互质的正整数,c是整数,且方程ax+by=c

(1)有一组整数解x0,y0则此方程的一切整数解可以表示为x=x0+bt;y=y0-at;t∈z;

(2)方程at+bp=c左右两边同除以gcd(a,b),得a1t+b1p=c1,再解最小正整数线性组合得一组解x1,y1,

    则所求方程的一组解为T=x1*c1,P=y1*c1,根据(2)式可得t的最小正整数解为(T%b1+b1)%b1,此即为可行时所求解,

注意:因为所给数据比较大,这里全部用__int64。

代码如下:

 1 #include <iostream>

 2 using namespace std;

 3 

 4 __int64 t, p;

 5 __int64 get_gcd(__int64 a, __int64 b){

 6     return !b?a:get_gcd(b, a%b);

 7 }

 8 

 9 void extended_gcd(__int64 a, __int64 b){

10     if (!b){

11         t = 1;

12         p = 0;

13     }

14     else{

15         __int64 temp;

16         extended_gcd(b, a%b);

17         temp = t - a / b*p;

18         t = p;

19         p = temp;

20     }

21 }

22 

23 int main(){

24     __int64 x, y, n, m, L, gcd;

25     cin >> x >> y >> m >> n >> L;

26     if (m == n){

27         cout << "Impossible" << endl;

28         return 0;

29     }

30     __int64 a, b, c, c1;

31     a = n - m;

32     b = L;

33     c = x - y;

34     gcd = get_gcd(a, b);

35     c1 = c%gcd;

36     if (c1 != 0){

37         cout << "Impossible" << endl;

38         return 0;

39     }

40     c /= gcd;

41     a /= gcd;

42     b /= gcd;

43     extended_gcd(a, b);

44     t *= c;

45     p *= c;

46     t = (t%b + b) % b;

47     cout << t << endl;

48     return 0;

49 }
View Code

 

当然也可以这么写:

 

d为n-m和L的最大公约数,x为(n-m)/d对L/d的逆元,即((n-m)/d) * x ≡ 1(mod L/d),即((n-m)/d) * x + (L / d)* y = 1的一组解,

所以((m-m)/d) * x + (L / d)* y = (x-y)/d的一组解为x0 = (x-y)/d * x.这也是(n - m) * x+ L * y = (x - y)的一组解。 (代码中cycle代表d)。

 1 #include<iostream>

 2 using namespace std;

 3 long gcd(long a, long b){

 4     return !b ? a : gcd(b, a%b);

 5 }

 6 int main(){

 7     long x, y, m, n, L, i, cycle;

 8     while (cin >> x >> y >> m >> n >> L){

 9         if (m > n) cycle = (y - x + L) % L;

10         else{

11             cycle = (x - y + L) % L;

12             swap(m, n);

13         }

14         if (n == m || cycle%gcd(L, m - n)){

15             cout << "Impossible" << endl;

16             continue;

17         }

18         for (i = 0;; i++){

19             if ((i*L + cycle) % (m - n) == 0){

20                 cout << (i*L + cycle) / (m - n) << endl;

21                 break;

22             }

23         }

24     }

25     return 0;

26 }
View Code

 

你可能感兴趣的:(poj)