POJ 1061 青蛙的约会

假设两只青蛙跳k次之后相遇,则需要满足:

x + km ≡ y + kn (mod L)

即 (x - y) + (m - n) * k ≡ 0 (mod L)

(x - y) = (n - m) * k + L * k'

最终就是求同余方程 ax + by = n的最小正整数解

数论中关于最大公约数有一个性质:存在整数x, y使gcd(a, b) = ax + by

所以若gcd(a, b) | n,则方程ax + by = n有解;否则无解


求同余方程解可使用扩展欧几里得算法

扩展欧几里得算法原理:

a * x0 + b * y0 = gcd(a, b)

b * x1 + (a % b) * y1 = gcd(b, a % b)

又gcd(a, b) = gcd(b, a % b)

则a * x0 + b * y0 = b * x1 + (a % b) * y1

由于a % b = a - a / b * b

所以 a * x0 + b * y0 = b * x1 + (a - a / b * b) * y1

x0 * a + y0 * b = y1 * a + (x1 - a / b * y1) * b

即x0 = y1,y0 = x1 - a / b * y1


最后一个问题就是怎么求出最小正整数解

假设求出的x0, y0为同余方程的一组解

则 a * x0 + b * y0 = n成立

又a * x + b * y = n

两式相减可得:a * (x - x0) + b * (y - y0) = 0

设d = gcd(a , b),上式两侧同时除以d可得:a / d * (x - x0) + b / d * (y - y0) = 0

此时gcd(a / d, b / d) = 1必然成立,所以

(b / d) | (x - x0) 即 x - x0 = (b / d) * t

最终 x = x0 + (b / d) * t

令r = b / d则

 (x0 % r + r) % r 肯定能够找到[0, r)上的解


这篇blog解释的更加详细:http://www.cnblogs.com/comeon4mydream/archive/2011/07/18/2109060.html

#include <stdio.h>

long long gcd(long long m, long long n)
{
	long long t;

	while (n != 0)
	{
		t = m % n;
		m = n;
		n = t;
	}
	return m;
}

void gcd_ext(long long a, long long b, long long *px, long long *py)
{
	long long t;

	if (b == 0)
	{
		*px = 1;
		*py = 0;
	}
	else
	{
		gcd_ext(b, a % b, px, py);
		t   = *py;
		*py = *px - *py * (a / b);
		*px = t;
	}
}

int main(void)
{
	long long x, y, m, n, l, d, s, t, r;

	while (scanf("%lld %lld %lld %lld %lld", &x, &y, &m, &n, &l) != EOF)
	{
		d = x - y;
		s = n - m;
		t = gcd(s, l);

		if (d % t != 0)
		{
			printf("Impossible\n");
		}
		else
		{
			r = l / t;
			gcd_ext(s / t, l / t, &x, &y);
			printf("%lld\n", ((x * (d / t) % r) + r) % r);
		}
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值