• 青蛙的约会


    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
  • 相关阅读:
    找出占用磁盘空间最大的前10个文件或文件夹
    把inline函数的定义放在头文件中
    判断是大端字节序还是小端字节序
    在source insight 中添加系统字体
    C++ inline 函数
    标准I/O函数库的三类缓冲
    内存分配失败错误处理
    P1765 手机
    P1321 单词覆盖还原
    P1308 [NOIP2011 普及组] 统计单词数
  • 原文地址:https://www.cnblogs.com/hbhdhd/p/12175678.html
Copyright © 2020-2023  润新知