zoukankan      html  css  js  c++  java
  • poj1061-青蛙的约会-(贝祖定理+扩展欧几里得定理+同余定理)

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

    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 Outp

    4

    前置技能:同余定理→欧几里得定理→贝祖定理→扩展欧几里得定理
    贝祖定理:设a,b是整数,则存在整数x,y,使得ax+by=gcd(a,b)
    扩展欧几里得定理:求解满足贝祖定理的一组解,即求x,y
    求解过程:
    对于gcd(a,b)必有ax+by=gcd(a,b),设a>b
    1. b=0时,gcd(a,b)=a,此时x=1,y0
    2. a>b>0时,设gcd(a,b) = d = gcd(b,a%b) 终有一次递归使得a%b=0,此时return gcd函数中的第一个参数
    设ax1 + by1 = gcd(a,b) = d
    = bx2 + (a%b)y2 = gcd(b,a%b) = d
    ∴ ax1 + by1 = bx2 + (a%b)y2
    = bx2 + ( a-[a/b]*b )y2 //[a/b]表示对a/b取整,a-[a/b]*b=a%b
           = ay2 + bx2 -[a/b]*by2
           = ay2 + b( x2-[a/b]*y2 )
    显然 x1=y2, y1=x2-[a/b]*y2
    gcd函数无限递归则可以得到 xi = y(i+1) , yi = x(i+1) - [a/b]*y(i+1)
    而终有一次gcd递归使得第二个参数为0,开始返回。

    解题过程:
    青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。
    青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。
    纬度线是一个圈,跳过尽头又从起点开始,显然是对L求余,如果位置坐标求余后相等,则可以碰面
    设跳跃次数为t,则每次跳跃后,青蛙A的坐标是(x+mt)%L,青蛙B的坐标是(y+nt)%L
    有解的情况是:
    (x+mt)%L = (y+nt)%L
    (x+mt -y-nt)%L = 0
    (x+mt -y-nt)%L = 0%L
    (m-n)t + (x-y) = 0 (mod L)
    (m-n)t = (y-x) (mod L)
    (m-n)t + 0 = (y-x) (mod L)
    (m-n)t + Lk = (y-x) (mod L)
    形如贝祖定理 ax+by = gcd(a,b)
    a=(m-n),
    b=L=0,
    multiple * gcd(a,b)= (y-x), //x和y是题目的起始坐标
    x=t, //x是贝祖定理的a解
    y=k, //y是贝祖定理的b解
    只需要保证题目中的y-x是gcd的倍数就好了
    套用欧几里得公式的话,默认解是gcd,题目中的(y-x)只要是gcd的倍数就有解,并且答案解是默认解的倍数
    本题的大坑在于负数解!!!
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<math.h>
    #include<string>
    #define ll long long
    #define inf 0x3f3f3f3f
    using namespace std;
    // ax + by = gcd(a,b)
    ll exgcd(ll a,ll b,ll &x,ll &y)//扩展欧几里德定理
    {
        if(b==0)//终有一次a%b传进来是0,递归出口
        {
            x=1;y=0;
            return a;
        }
        ll q=exgcd(b,a%b,y,x);
        //最终递归出来,y1=1,x1=0
        y=y-(a/b)*x;
        //后面的y相当于下一个递归的x2,x相当于下一个递归的y2,符合推导公式
        //x1=y2;   y1=x2-[a/b]*y2;
        return q;
    }
    
    int main()
    {
        ll x,y,m,n,l,c;
        while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l)!=EOF)
        {
            ll t,k,gcd;
            gcd=exgcd(m-n,l,t,k);///欧几里得扩展公式的右边默认是gcd,gcd不需要传进去,t是默认解
            ll multiple=(y-x)/gcd;///如  果右边是gcd的倍数有解,结果也是默认解的某倍
    
            if( (x-y)%gcd!=0 )
                printf("Impossible
    ");
            else
                printf("%lld
    ", ((t*multiple)%l+l)%l );///gcd如果是负的,求模后,加模数再求模
            /*
            样例中, gcd=-1,
            (t*倍数+l)%l则WA,举例:如果t*gcd=-11,l=5,则-6%5=-1
            先模再加再模则AC:保证先模后的数在[-l,l]之间,加l再模保证结果是正数*/
        }
        return 0;
    }
    
    
  • 相关阅读:
    hdu 5446 Unknown Treasure lucas和CRT
    Hdu 5444 Elven Postman dfs
    hdu 5443 The Water Problem 线段树
    hdu 5442 Favorite Donut 后缀数组
    hdu 5441 Travel 离线带权并查集
    hdu 5438 Ponds 拓扑排序
    hdu 5437 Alisha’s Party 优先队列
    HDU 5433 Xiao Ming climbing dp
    hdu 5432 Pyramid Split 二分
    Codeforces Round #319 (Div. 1) B. Invariance of Tree 构造
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/10359061.html
Copyright © 2011-2022 走看看