PKU-1061 青蛙的约会 (扩展的欧几里德算法)

原题链接  http://poj.org/problem?id=1061

青蛙的约会

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

 

解题报告链接 http://www.cnblogs.com/comeon4mydream/archive/2011/07/18/2109060.html

Source Code

/*
同余问题、扩展的欧几里德算法(欧几里德算法又称辗转相除法)

扩展欧几里德定理(常用在求解模线性方程及方程组中):
  
	对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整
	
数对 x,y ,使得 gcd(a,b)=ax+by。


根据题意,两个青蛙跳到同一个点上才算是遇到了,所以有 (x+m*t) - (y+n*t) = p * l; 

(t是跳的次数,p是a青蛙跳的圈数跟b青蛙的圈数之差。整个就是路程差等于纬度线周长的整数倍),

转化一下: (n-m) * t + l * p = x – y;
  
令 a = n-m,  b = l,  c = gcd(a, b),  d = x-y;
	
有 a * t + b * p = d;   (1)

要求的是t的最小整数解。
		
用扩展的欧几里德求出其中一组解t0 ,p0, 并令c = gcd(a, b);
		  
有 a * t0 + b * p0 = c;  (2)
			
因为c = gcd(a, b), 所以 a * t / c是整数,b * t / c 也是整数,所以 d / c 也需要是整数,否则无解。

(2)式两边都乘(d / c) 得 a * t0 *(d / c) + b * p0 * (d / c) = d;
				
所以t0 * (d / c)是最小的解,但有可能是负数。

定理二:若gcd(a, b) = 1,则方程ax ≡ d (mod b)在[0, b-1]上有唯一解。

定理三:若gcd(a, b) = c,则方程ax ≡ d (mod b)在[0, b/c - 1]上有唯一解。

  令 r = b / c;
					
所以解为 (t0 * (d / c) % r + r) % r;
					  
还有一个问题,如何用扩展的欧几里德求出t0跟p0呢?
						
对于不完全为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;
											  
		由此可以得出扩展欧几里德的递归程序:

*/


#include <iostream>
using namespace std;

//返回的为a,b的最大公约数
long long extgcd(long long a, long long b, long long &x, long long &y)
{
	
    long long d, temp;
	
    if (b == 0) { x = 1; y = 0; return a; }
	
    d = extgcd(b, a % b, x, y);
	
    temp = x - a / b * y; x = y; y = temp;
	
    return d;	
}

int main() {
	long long x, y, m, n, l, result, X, Y, r;
	while (scanf("%I64d %I64d %I64d %I64d %I64d", &x, &y, &m, &n, &l) != EOF) {
		result = extgcd(n - m, l, X, Y);
		if ((x - y) % result) {
			printf("Impossible\n");
		} else {
			r = l / result;
			printf("%d\n", ((x - y) / result * X % r + r) % r);
		}
	}
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值