SGU141 Jumping joe

本文通过一个具体的数学问题,介绍了如何运用扩展欧几里得算法求解特定类型的方程组。通过对手推公式的详细步骤进行解析,并结合编程实现,展示了算法的具体应用过程。

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

又用到了扩展欧几里得,这题其实主要是手推公式... 草稿纸被我扔进垃圾桶N次,又被我捡回来N次...T_T

首先发现 (p1-n1)x1+(p2-n2)x2 =p,又是整数解,联想扩展欧几里得

p1-n1=s

p2-n2=t

p1+n1+p2+n2=k

p1>=0,p2>=0,n1>=0,n2>=0

进一步推得

2*(n1+n2)=k-s-t

n1>=max(0,-s)

n2>=max(0,-t)

再推

2*(n1+n2)>=2*(max(0,-s)+max(0,-t))

2*(n1+n2)=k-s-t

问题转换为判断是否存在n1,n2满足上面两个式子,也就是判断是否存在s,t 使得 k-s-t>=2*(max(0,-s)+max(0,-t))

看起来好像还是很复杂... 继续推一下,讨论s,t的正负。

讨论过后发现问题变成了找s,t 使得  k>=fabs(s)+fabs(t)

我们利用扩展欧几里得已经求得了两个特解s0,t0 而s=s0+k'*x2/gcd(x1,x2) ;t=t0-k'*x1/gcd(x1,x2),其实直接让我求最值我没想出来怎么做...但是我们可以枚举k',从-40000到40000枚举一遍,求得最值(这...全凭既视感= =|||),找最值的过程注意还要满足k-s-t是2的倍数这个条件。

找到最值后,判断一下k>=fabs(s)+fabs(t)即可。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
void ex_gcd(LL a,LL b,LL &x,LL &y,LL &d)
{
    if(b==0)
    {
        x=1,y=0,d=a;
        return ;
    }
    else
    {
        ex_gcd(b,a%b,x,y,d);
        int t=x;
        x=y;
        y=t-a/b*y;
        return ;
    }
}
int main()
{
    LL x1,x2,p,k,p1,n1,p2,n2,s,t,d,tt1,tt2,m,fs,ft,i;
    bool find;
    scanf("%lld %lld %lld %lld",&x1,&x2,&p,&k);
    ex_gcd(x1,x2,s,t,d);
    if(p%d!=0)
    {
        printf("NO\n");
        return 0;
    }
    s*=p/d,t*=p/d;
    tt1=x2/d,tt2=x1/d;
    find=false;
    s-=40000*tt1;t+=40000*tt2;
    for(i=-40000;i<=40000;++i)
    {
        if((k-s-t)%2==0&&(!find||fabs(s)+fabs(t)<m))
        {
            m=fabs(s)+fabs(t);
            fs=s;
            ft=t;
            find=true;
        }
        s+=tt1,t-=tt2;
    }
    if(find&&k>=m)
    {
        printf("YES\n");
        n1=max(0LL,-fs);n2=(k-fs-ft-2*n1)/2;p1=fs+n1;p2=ft+n2;
        printf("%lld %lld %lld %lld\n",p1,n1,p2,n2);
    }
    else
    {
        printf("NO\n");
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值