扩展欧几里得算法的应用 POJ 2115 POJ 2142 POJ 1061 HDU 2669 HDU 1576 SGU 106

本文详细介绍了扩展欧几里得算法,并通过具体实例展示了如何利用该算法解决实际问题,包括青蛙约会问题及循环次数预测等。

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

LL exgcd(LL a,LL b,LL &x,LL &y)
 {
    LL r,t;
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    r=exgcd(b,a%b,x,y);
    t=x;
    x=y; 
    y=t-a/b*y;
    return r;
}

 

求a * x + b * y = c一组整数解的步骤:

1、计算g=gcd(a,b),如果c%g!=0,即c不能被g整除,则无整数解,不再继续下面的步骤。

      特别的,如果已经知道a * x + b * y = c一定有解,可跳过这一步。
2、通过g=exgcd(a,b,x',y')(g为a、b最大公约数)得到方程a * x + b * y = gcd(a,b) =g的一组解x'、y';

3、x=x'*c/g、y=y'*c/g(不能先除后乘)得到方程a * x + b * y = c的一组特解x、y;
4、通过特解可得方程a * x + b * y = c的通解为:

x = x + (b/g) * t
y = y - (a/g) * t
(t为整数)
 
 
应用
1、求x(或y)的最小非负解
方法: x=(x%(b/g)+b/g)%(b/g)y=(y%(a/g)+a/g)%(a/g)
 
POJ 1061 青蛙的约会
 

题意:两个青蛙在赤道上跳跃,走环路。起始位置分别为x,y。每次跳跃距离分别为m,n。赤道长度为L。两青蛙跳跃方向与次数相同的情况下,问两青蛙是否有方法跳跃到同一点。输出最少跳跃次数。

分析:扩展欧几里德。设两青蛙跳了s步。有方程:(x+n*s)-(y+m*s)=k*L。整理得:(n-m)*s+L*(-k)=y-x.接下来只用按就方程ax+by=c的步骤写就行了。

 
#include<stdio.h>
__int64 exgcd(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
    __int64 r,t;
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    r=exgcd(b,a%b,x,y);
    t=x;
    x=y; 
    y=t-a/b*y;
    return r;
}
int main()
{
    __int64 x,y,m,n,l,xx,yy,g,r;
    scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&l);
    g=exgcd(n-m,l,xx,yy);
    if((x-y)%g!=0) printf("Impossible\n");
    else {
            xx=xx*(x-y)/d;
            r=l/d;
            xx=(xx%r+r)%r;//求出最小非负整数解
            printf("%I64d\n",xx);
        }
    return 0;
}

POJ 2115 C Looooops
 
题意:

对于C的for(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次才会结束。

若在有限次内结束,则输出循环次数。

否则死循环,输出FOREVER。

思路:

题意不难理解,只是利用了 k位存储系统 的数据特性进行循环。

例如int型是16位的,那么int能保存2^16个数据,即最大数为65535(本题默认为无符号),

当循环使得i超过65535时,则i会返回0重新开始计数

如i=65534,当i+=3时,i=1

其实就是 i=(65534+3)%(2^16)=1

据此我们得到方程c*x=(b-a)%2^k

然后根据扩展欧几里得算法解就行了,不用b-a不是系数,所以不用考虑其正负

注意:k <=32 ,而 2^32超出整数范围,所以要用__int64或long long ,也就是LL B=(LL)1<<k

 

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int M = 100050;
typedef long long LL;

LL gcd( LL x,LL y )
{
    return y ? gcd( y , x % y ) : x;
}

LL exgcd(LL a, LL b, LL & x, LL & y)
{
    if (b == 0)
    {
        x=1;
        y=0;
        return a;
    }
    LL d = exgcd(b, a % b, x, y);
    LL t = x;
    x = y;
    y = t - a / b * y;
    return d;
}

int main(){
    //freopen("in.txt","r",stdin);
    LL a,b,c,k;
    while(scanf("%lld%lld%lld%lld",&a,&b,&c,&k)!=EOF){
        if(!(a||b||c||k)) break;
        LL A=c,B=((LL)1<<k),C=b-a,g,x,y;
        g=gcd(A,B);
        if(C%g!=0)
            printf("FOREVER\n");
        else{
            A/=g;B/=g;C/=g;
            exgcd(A,B,x,y);
            x*=C;
            x=(x%B+B)%B;
            cout<<x<<endl;
        }
    }
    return 0;
}
 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值