poj1061 青蛙的约会(扩展欧几里得)

本文介绍了一道经典的数论题目——青蛙约会问题,并详细解析了解决该问题所使用的扩展欧几里得算法。通过实例代码展示了如何求解不定方程的整数解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值