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

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

    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

    题意就是解一个方程,即(x+m*t)-(y+n*t)=p*L。求满足方程的最小t。将方程变换为(n-m)*t+p*L=x-y。这个方程里面x,y,n,m都已知。

    一开始不知道扩展欧几里得的方法,就一直遍历判断看能不能有符合条件的数值,提交了44次还是TLE。。。

    (摘自百度百科)扩展欧几里德:

    扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。

    欧几里德算法

    概述

    欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:gcd函数就是用来求(a,b)的最大公约数的。gcd函数的基本性质:gcd(a,b)=gcd(b,a)=gcd(-a,b)=gcd(|a|,|b|)

    公式表述

    gcd(a,b)=gcd(b,a mod b)

    证明:a可以表示成a = kb + r,则r = a mod b

    假设d是a,b的一个公约数,则有d|a, d|b,而r = a - kb,因此d|r。因此d是(b,a mod b)的公约数。

    假设d 是(b,a mod b)的公约数,则d | b , d |r ,但是a = kb +r,因此d也是(a,b)的公约数

    因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。

    C++语言实现

    <span style="font-size:12px;">#include<iostream>
    #include<cstdio>
    using namespace std;
    int x,y,q;
    void extend_Eulid(int a,int b){
    if(b==0){
    x=1;y=0;q=a;
    return;
    }
    extend_Eulid(b,a%b);
    int temp=x;
    x=y;
    y=temp-a/b*y;
    }
    int main(){
    int a,b;
    cin>>a>>b;
    extend_Eulid(a,b);
    printf("%d=(%d)*%d+(%d)*%d
    ",q,x,a,y,b);
    return 0;
    }</span>
    扩展算法

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

    c++语言实现

    <pre name="code" class="html">int exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(a==0)
        {
            x=0;y=1;
            return b;
        }
        else
        {
            ll tx,ty;
            ll d=exgcd(b%a,a,tx,ty);
            x=ty-(b/a)*tx;
            y=tx;
            return d;
        }
    }
    求解 x,y的方法的理解
    设 a>b。
    1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
    2,ab<>0 时
    设 ax1+ by1= gcd(a,b);
    bx2+ (a mod b)y2= gcd(b,a mod b);
    根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
    则:ax1+ by1= bx2+ (a mod b)y2;
    即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
    也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
    根据恒等定理得:x1=y2; y1=x2- [a / b] *y2;
    这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
    上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。

    代码:

    #include <iostream>
    #include <vector>
    #include <string>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    long long d;
    
    void ex_gcd(long long a,long long b,long long &xx,long long &yy)
    {
    	if(b==0)
    	{
    		xx=1;
    		yy=0;
    		d=a;//d为求出来的a,b的最小公约数
    	}
    	else
    	{
    		ex_gcd(b,a%b,xx,yy);
    		
    		long long t=xx;
    		xx=yy;
    		yy=t-(a/b)*yy;
    	}
    }
    
    int main()
    {
    	long long x,y,m,n,L,xx,yy;
    	cin>>x>>y>>m>>n>>L;
    
    	ex_gcd(n-m,L,xx,yy);
    
    	if((x-y)%d)//如果方程等式右边不能除以最小公约数,说明该方程没有解。
    	{
    		cout<<"Impossible"<<endl;
    	}
    	else
    	{
    		xx=xx*((x-y)/d);//求出的xx,yy是方程等于最小公约数时的解,这时要将解扩大为(x-y)*d倍。
            long long r=L/d;
            xx=(xx%r+r)%r;//此处求解的最小值
            cout<<xx<<endl;
    	}
    	system("pause");
    	return 0;
    }
    




    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    ubuntu
    ubuntu
    ubuntu14.04,安装Gnome 15.10 (桌面)
    ubuntu14.04,安装Gnome 15.10 (桌面)
    Ubuntu 14.04.3 LTS如何安装谷歌输入法
    Ubuntu 14.04.3 LTS如何安装谷歌输入法
    ubuntu 安装 删除 卸载 Deb 包文件
    失去爆破音规律
    单词发音规律
    英式音标和美式音标的差异
  • 原文地址:https://www.cnblogs.com/lightspeedsmallson/p/4785870.html
Copyright © 2011-2022 走看看