http://poj.org/problem?id=1061
题意:中文题,求青蛙跳多少次才可以碰面,碰面即约会。
思路:数论第一题。根据题意很容易得出这个周期问题的条件:(x+mt)-(y+nt) = kl。其中t代表跳了多少次,k代表相差多少圈,这两个都是未知数。变形一下得到(n-m)t+lk = x-y,这就相当于解ax+by = c的式子了。其中a = n-m,b = l, c = x-y, 均为整数。
首先判断他是否有整数解。对于ax+by = c的不定方程,如果c能被gcd(a,b)整除,那么就有整数解。因为左边除以最大公约数后,两个数互为素数,比如8和10除以gcd后变为4和5,互为素数的两个数通过x和y可以组成任意大小的整数(个人理解),c/gcd也就是其中之一了,只要满足是整数即可。这样我们就需要算出gcd(a,b)的值,但我们要求的是解的大小,这个必须要在求gcd的过程中与其同步,于是就有了扩展欧几里得算法。
给出模板:
int ext_gcd(ll a, ll b, ll &x, ll &y)//添加引用确保同步更新
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
ll d = ext_gcd(b, a%b, x, y);
ll tmp = x;
x = y;
y = tmp - (a/b)*y;
return d;
}
当b==0的时候,a就是最大公约数,所以令x=1和y=0。当b != 0时,设x1和y1为当前的x和y,x2和y2为上一次的x和y,则:
ax1+by1 = gcd(a,b) = gcd(b,a%b) = bx2+(a%b)y2 = bx2+(a-a/b*b)y2 = ay2+b(x2-(a/b)y2)
这里x1由上一次的y2得来,y1由上一次的x2-(a/b)y2得来,所以每次递归完毕后都要在普通的gcd上面加这两个更新。
最后求的t值实际上就是x,只不过这个x是相对于gcd的,我们这里变成c后就多了个倍数,记得乘上。
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
int ext_gcd(ll a, ll b, ll &x, ll &y)//添加引用确保同步更新
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
ll d = ext_gcd(b, a%b, x, y);
ll tmp = x;
x = y;
y = tmp - (a/b)*y;
return d;
}
int main()
{
// freopen("in.txt", "r", stdin);
ll a, b, c, d;
ll x, y, m, n, l;
while(~scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &l))
{
ll t, k;//代表两个未知数
a = n-m;
b = l;
c = x-y;
d = ext_gcd(a, b, t, k);
if(c%d != 0)
{
printf("Impossible\n");
continue;
}
t = t*(c/d);//通过扩展欧几里得求出的x,是c为gcd(a, b)时候的,需要乘以倍数
t = (t%b+b)%b;//先排除负数的情况,再保证跳的次数不要超过l
printf("%lld\n", t);
}
return 0;
}