青蛙的约会

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

题意:大体就是A在x处开始跳,每次跳m,b在y处开始,每次跳n问两个能否相遇,路径总长度为L,是循环的一个环。
思路:数论题,用到的是扩展欧几里得,好吧是我太菜了一直没搞懂这个算法。
首先可以得出一个方程[x+k*m](mod L)≡[y+k*n](mod L),可以转化为(n-m) * k ≡ x-y (mod L),
进而得到(m-n)*k+s*L=y-x(好吧这个转换不会,从大佬那抄来的),
现在已经符合ax+by=c的方程了,设a=m-n,b=L,c=y-x,然后套用模板求出特解k的值,注意k>0,所以要用通解公式得出最小正整数。
用到三个定理:

1 gcd(a,b)是ax+by的线性组合的最小正整数,x,y∈z;如果d = gcd(a, b),则必能找到正的或负的整数k和l,使d = a*k + b*l

2 如果ax+by=c,x,y∈z;则c%gcd(a,b)==0;若gcd(a, b)=1,则方程ax ≡ c (mod b)在[0, b-1]上有唯一解。

3 如果是互质的正整数,是整数,且方程ax+by=c,有一组整数解x0,y0则此方程的一切整数解可以表示为x=x0+bt;y=y0-at;t∈z;

用扩展的欧几里德求出其中一组解t0 ,p0, 并令d = gcd(a, b),有 a * t0 + b * p0 = d;  (2)

 (2)式两边都乘(c/ d) 得 a * t0 *(c / d) + b * p0 * (c / d) = d* (c/d)=d;

因为d = gcd(a, b), 所以 a * t0/ d是整数,b * p0 / d 也是整数,所以 c/ d 也需要是整数,否则无解。

 所以t0 * (c / d)是最小的解,但有可能是负数。

因为a * ( t0 *(c / d) + b*n) + b * (p0 * (c / d) – a*n) = c; (n是自然数),所以解为 (t0 * (c / d) % b + b)%b。 

 

关于扩展欧几里得:

 对于不完全为0的非负整数a, b  gcd(a, b)表示a, b 的最大公约数。那么存在整数x, y使得 gcd(a, b) = a * x + b * y;

不妨设a > b

 ①,当b = 0 时,gcd(a, b) = a , 此时 x = 1, y = 0;

 ②,当 a * b 大于或小于 0 时,

 设 a * x + b * y = gcd(a, b);   (1)

    b * x0 + (a % b) * y0 = gcd( b, a % b);   (2)

由欧几里德公式: gcd(a, b) = gcd (b, a % b);得(1),(2) 

 a * x + b * y = b * x0 + (a % b) * y0

                     = b * x0 + (a – a / b * b) * y0               

                     = a * y0 + ( x0 – a / b * y0 ) * b

   所以 x = y0, y = x0 – a / b * y0;

  由此可以得出扩展欧几里德算法。

 代码:

  1 #include <map>
  2 #include <set>
  3 #include <list>
  4 #include <stack>
  5 #include <queue>
  6 #include <deque>
  7 #include <cmath>
  8 #include <ctime>
  9 #include <string>
 10 #include <limits>
 11 #include <cstdio>
 12 #include <vector>
 13 #include <iomanip>
 14 #include <cstdlib>
 15 #include <cstring>
 16 #include <istream>
 17 #include <iostream>
 18 #include <algorithm>
 19 #define ci cin
 20 #define co cout
 21 #define el endl
 22 #define Scc(c) scanf("%c",&c)
 23 #define Scs(s) scanf("%s",s)
 24 #define Sci(x) scanf("%d",&x)
 25 #define Sci2(x, y) scanf("%d%d",&x,&y)
 26 #define Sci3(x, y, z) scanf("%d%d%d",&x,&y,&z)
 27 #define Scl(x) scanf("%I64d",&x)
 28 #define Scl2(x, y) scanf("%I64d%I64d",&x,&y)
 29 #define Scl3(x, y, z) scanf("%I64d%I64d%I64d",&x,&y,&z)
 30 #define Pri(x) printf("%d
",x)
 31 #define Prl(x) printf("%I64d
",x)
 32 #define Prc(c) printf("%c
",c)
 33 #define Prs(s) printf("%s
",s)
 34 #define For(i,x,y) for(int i=x;i<y;i++)
 35 #define For_(i,x,y) for(int i=x;i<=y;i++)
 36 #define FFor(i,x,y) for(int i=x;i>y;i--)
 37 #define FFor_(i,x,y) for(int i=x;i>=y;i--)
 38 #define Mem(f, x) memset(f,x,sizeof(f))
 39 #define LL long long
 40 #define ULL unsigned long long
 41 #define MAXSIZE 100005
 42 #define INF 0x3f3f3f3f
 43 
 44 const int mod=1e9+7;
 45 const double PI = acos(-1.0);
 46 
 47 using namespace std;
 48 
 49 LL exgcd(LL a,LL b,LL &x,LL &y)
 50 {
 51     int d=a;
 52     if(b!=0)
 53     {
 54         d=exgcd(b,a%b,y,x);
 55         y-=(a/b)*x;
 56     }
 57     else
 58     {
 59         x=1;
 60         y=0;
 61     }
 62     return  d;
 63 }
 64 //函数的返回值是a、b的最大公约数
 65 //传进来x、y的引用,进而得到x、y的值
 66 
 67 int main()
 68 {
 69     LL n,m,x,y,l;
 70     cin>>x>>y>>m>>n>>l;
 71     LL a,b,c;
 72     a=n-m;;
 73     b=l;
 74     c=x-y;
 75     LL r=exgcd(a,b,x,y);//这个扩展欧几里得函数求得是a,b的最大公约数以及ax+by=gcd(a,b)的解x、y
 76     if(c%r!=0)
 77         Prs("Impossible");
 78     else
 79     {
 80         x=x*c/r;//得到方程 (n-m)k+l*s=x-y的解
 81         //因为解可能有负数,所以判断一下
 82         if(x>=0)
 83             x%=b/r;
 84         else
 85             x=(x%b/r+b/r);
 86         co<<x;
 87     }
 88     //cout<<exgcd(12,23,x,y);
 89     return 0;
 90 }
 91 /*
 92 关于解的大小问题:
 93 ax + by = c 的通解公式
 94 x=x1+k*(b/gcd(a,b))
 95 y=y1-k*(a/gcd(a,b))  k为任意整数
 96 注意x与y是一个增加一个减少的。
 97 
 98 所以在本题中在x大于0的时候我们应该进行取模,防止两个青蛙周期跳
 99 当x小于0的时候就加上b/r取模,但x可能是一个很大的负数,所以可以先取模在加上b/r保证得到正数
100 */
View Code
原文地址:https://www.cnblogs.com/hbhdhd/p/12175678.html