POJ 1061 青蛙的约会(拓展欧几里得求同余方程,解ax+by=c)

青蛙的约会
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 122871   Accepted: 26147

Description

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

Input

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

Output

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

Sample Input

1 2 3 4 5

Sample Output

4

Source

 

题目分析

首先,我们可以轻松的列出方程: 
设走了t步,x,y,m,n,L含义如题。 
x+m*t≡y+n*t (mod L) 
移项:(x-y)+t(m-n)≡0(mod L) 
这个式子等价于(x-y)+t(m-n)=kL 
//t和k才是未知数

再移项:kL-t(m-n)=(x-y) 
为了化出不定方程的标准形式(不化也可以),再改成: 
kL+t(n-m)=(x-y) 
n-m=p,x-y=q 
kL+tp=q 
//再次重申,t和k才是未知数! 
上式已经是标准的不定方程了,然后怎么解它呢?

以下是重点 
首先,它有解的前提是gcd(L,p)|q。(整除符号,不是或运算(QωQ)) 
所以我们先求gcd(L,p)。做一次拓欧,求出gcd(L,p),同时我们求出了(拓欧的)x0,y0先放着。(为了不和题目的x,y冲突) 
接着,如果gcd(L,p)不整除q,那么之后无法做下去了,此题无解。 
这里写图片描述

 

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<algorithm>
 5 usingnamespace std;
 6 
 7 __int64 x,y,a,b,c,d;
 8 __int64 n,m,X,Y,L;
 9 
10 __int64 gcd(__int64 a,__int64 b)
11 {
12     __int64 t,d;
13     if(b==0)
14     {
15         x=1;
16         y=0;
17         return a;
18     }
19     d=gcd(b,a%b);
20     t=x;
21     x=y;
22     y=t-(a/b)*y;
23     return d;
24 }
25 
26 int main()
27 {
28     while(scanf("%I64d%I64d%I64d%I64d%I64d",&X,&Y,&m,&n,&L)==5)
29     {
30         a=n-m;
31         b=L;
32         c=X-Y;
33         d=gcd(a,b);
34         if(c%d!=0)
35         {
36             printf("Impossible
");
37             continue;
38         }
39         x=x*(c/d);
40         y=y*(c/d);
41 
42         /*通解:
43         x1=x+b/d*t;
44         y1=y-a/d*t;
45         t为任意整数
46         */
47         //找最小的x1,即求x+b/d*t最小,那么只有t为某一个数时才最小
48         //显然t必须与x正负相反才有最小,那么就看做x-b/d*t,这个式子的最小值便是t=x/(b/d)时,注意这是整型除法
49         __int64 k=x*d/b;
50         k=x-k*b/d;
51         if(k<0)
52             k+=b/d;
53         printf("%I64d
",k);
54     }
55     return0;
56 }
 1 #include <iostream>  
 2 #include <cstdio>  
 3 #include <cstring>  
 4 #include <cmath>  
 5 #include <vector>  
 6 #include <string>  
 7 #include <queue>  
 8 #include <stack>  
 9 #include <algorithm>  
10 
11 #define INF 0x7fffffff  
12 #define EPS 1e-12  
13 #define MOD 1000000007  
14 #define PI 3.141592653579798  
15 #define N 100000  
16 
17 using namespace std;  
18 
19 typedef long long LL;  
20 typedef double DB;  
21 
22 LL e_gcd(LL a,LL b,LL &x,LL &y)  
23 {  
24     if(b==0)  
25     {  
26         x=1;  
27         y=0;  
28         return a;  
29     }  
30     LL ans=e_gcd(b,a%b,x,y);  
31     LL temp=x;  
32     x=y;  
33     y=temp-a/b*y;  
34     return ans;  
35 }  
36 
37 LL cal(LL a,LL b,LL c)  
38 {  
39     LL x,y;  
40     LL gcd=e_gcd(a,b,x,y);  
41     if(c%gcd!=0) return -1;  
42     x*=c/gcd;  
43     b/=gcd;  
44     if(b<0) b=-b;  
45     LL ans=x%b;  
46     if(ans<=0) ans+=b;  
47     return ans;  
48 }  
49 
50 int main()  
51 {  
52     LL x,y,m,n,L;  
53     while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)!=EOF)  
54     {  
55         LL ans=cal(m-n,L,y-x);  
56         if(ans==-1) printf("Impossible
");  
57         else printf("%lld
",ans);  
58     }  
59     return 0;  
60 }  
View Code
 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <algorithm>
 5 using namespace std;
 6 long long x, y, m, n, l, k, t, d, va, vb, ba, bb;
 7 long long extgcd(long long a, long long b, long long &x, long long &y)
 8 {
 9     long long d = a;
10     if (b != 0)
11     {
12         d = extgcd(b, a%b, y, x);
13         y = y - a / b * x;
14     }
15     else
16     {
17         x = 1; y = 0;
18     }
19     return d;
20 }
21 int main()
22 {
23     cin >> ba >> bb >> va >> vb >> l;
24     m = va - vb; n = bb - ba;
25     d = extgcd(m, l, x, y);
26     if (n%d != 0)
27     {
28         puts("Impossible");
29         return 0;
30     }
31     t = l / d;
32     k = (x*(n / d) % t + t) % t;
33     if (k < 0) k += l;
34     cout << k << endl;
35     return 0;
36 }

ax+by=c问题

 

问题:ax+by=c,已知a、b、c,求解使该等式成立的一组x,y。其中a、b、c、x、y均为整数

 

a,b的最大公约数为gcd(a,b)。如果c不是gcd(a,b)的倍数,则该等式无解,因为等式左边除以gcd(a,b)是整数,

而等式右边除以gcd(a,b)后为小数。(根据解方程的时候,在等式的左右两边同时除以非0的整数,等式依然成立)

 

因此,只有当c是gcd(a,b)的倍数的时候,该等式有解。这样,可以通过计算使ax1+by1=gcd(a,b)成立的x1、y1,

然后有x=(c/gcd(a,b))*x1,y=(c/gcd(a,b))*y1,得到x,y。

 1 // 等式ax+by=c,已知a、b、c,求x和y。  
 2 // 解该线性方程等同于解同余式ax = c(mod b)  
 3 // 返回值表示是否有解,true有解,false无解  
 4 bool linear_equation(int a, int b, int c, int &x, int &y)  
 5 {  
 6     int n = extended_euclid(a, b, x, y);  
 7     if(c%n)  
 8         return false;  
 9     int k = c/n;  
10     x *= k;  
11     y *= k;  
12     return true;  
13 }  
原文地址:https://www.cnblogs.com/caiyishuai/p/13271198.html