zoukankan      html  css  js  c++  java
  • 青蛙的约会

    两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
    我们把这两只青蛙分别叫做青蛙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

    扩展欧几里德算法是用来求解ax+by=gcd(a,b)的解。
    --------------------------------------------------------------------------------------------------------------------
    首先欧几里德算法(辗转相除法)是求a和b的最大公因数,gcd(a,b) = gcd(b,a % b),直至a % b == 0,则b就是其最大公因数
    可以通过递归实现:
    int gcd(int a,int b) {
    if(b == 0)return a;
    return gcd(b,a % b);
    }
    --------------------------------------------------------------------------------------------------------------------
    而扩展算法为:对于不完全为0的非负整数a,b,gcd(a,b)表示a,b的最大公约数,必然存在整数对x,y,使得gcd(a,b) = ax + by。
    理解:
    ax + by = gcd(a,b) = gcd(b,a%b) = bx' + (a % b)y' = bx' + (a - (a / b) * b)y' = ay' + b(x' - (a / b)y')
    即:ax + by = ay' + b(x' - (a / b)y')
    则:x = y',y = x' - (a / b)y'
    设a > b,当b == 0时,gcd(a,b) = a,所以此时x = 1,y = 0;
    以此可以通过递归过程实现:
    int extgcd(int a,int b,int *x,int *y) {
    if(b == 0) {
    *x = 1;*y = 0;
       return a;
      }
     int r = extgcd(b,a % b,y,x);
      *y -= (a / b) * (*x);
    return r;
    }
    上面是求ax+by=gcd(a,b)的解的过程
    --------------------------------------------------------------------------------------------------------------------
    那么如何利用扩展算法求解方程a * x + b * y = n的整数解呢。
    1、先计算gcd(a,b),若n不能被gcd(a,b)整除,则方程无整数解;
    否则,在方程两边同时除以gcd(a,b),两边约分后得到新的不定方程a' * x + b' * y = n',
    此时gcd(a',b') = 1(因为已经除去了最大公约数);
    2、利用扩展算法求出方程a' * x + b' * y = 1的一组整数解x0,y0,
    则n' * x0,n' * y0是方程a' * x + b' * y = n'的一组整数解;
    3、根据数论中的相关定理,可得方程a' * x + b' * y = n'的所有整数解为:
    x = n' * x0 + b' * t
    y = n' * y0 - a' * t (t为任意整数)
    上面的解也就是a * x + b * y = n 的全部整数解
    --------------------------------------------------------------------------------------------------------------------
    本题:
    x + m * t - (y + n * t) = k * l
    即(n - m) * t + k * l = x - y
    先求r = gcd(n - m,l),如果x - y能被其整除,说明有解,否则没有解
    同时求(n - m) * t + k * l = r的解,即求(n - m) / r * t + l / r * k = 1的解t0和k0,
    再乘(x - y) / r,得到原方程的解,
    我们需要的是[0,l - 1]内的解。
    根据定理:若gcd(a, b) = 1,则方程ax ≡ c (mod b)在[0, b-1]上有唯一解。
    设rr = l / r,最后的解为 (t0 * (x - y) / r) % rr

    c++代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    using namespace std;
    long long exgcd(long long a,long long b,long long &x,long long &y)
    {
        if(b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        long long r = exgcd(b,a % b,x,y);
        long long t = x - a / b * y;
        x = y;
        y = t;
        return r;
    }
    int main()
    {
        long long x,y,m,n,l,a,b;
        cin>>x>>y>>m>>n>>l;
        long long r = exgcd(n - m,l,a,b);
        long long rr = l / r;
        if((x - y) % r)
        {
            cout<<"Impossible";
        }
        else
        {
            cout<<((x - y) / r * a % rr + rr) % rr;///a 只是 (n - m) * t + k * l = gcd(n - m,l) 的t对应解,需要乘(x - y) / gcd(n - m,l) 才是要求的方程的解
        }
    }

    c代码:

    #include <stdlib.h>
    #include <stdio.h>
    #define inf 0x3f3f3f3f
    #define MAX 10001
    long long extgcd(long long a,long long b,long long *x,long long *y) {
        if(b == 0) {
            *x = 1;
            *y = 0;
            return a;
        }
        long long r = extgcd(b,a % b,x,y);
        long long t = *x - (a / b) * (*y);
        *x = *y;
        *y = t;
        return r;
    }
    int main() {
        long long x,y,m,n,l,a,b;
        scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);
        long long r = extgcd(n - m,l,&a,&b);
        long long rr = l / r;
        if((x - y) % r)printf("Impossible");
        else {
            printf("%lld",((x - y) / r * a % rr + rr) % rr);
        }
    }
  • 相关阅读:
    最近ACM刷题见到的没见过的名词
    最近刷题常常遇见的需要百度的知识点
    简单RPG场景实现(改
    简单RPG场景实现
    位图载入与位图移动
    动态菜单
    静态菜单
    双人五子棋
    HDU 2112 HDU Today
    音痴又音痴的LT
  • 原文地址:https://www.cnblogs.com/8023spz/p/8836289.html
Copyright © 2011-2022 走看看