[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

 

posted @ 2015-06-16 13:26  繁夜  阅读(224)  评论(0编辑  收藏  举报