poj 2142 The Balance 扩展欧几里得

首先求出通项 X=x+b/d*t Y=y-a/d*t (x,y为ax+by=gcd(a,b)的解,d=gcd(a,b))可知我们要求的最小的解是 abs(x+b/d*t) + abs(y-a/d*t)

设a>b不是的话,就交换a,b,我们发现上述关于t的方程是 |x+k1*t| + |y-k2*t|,由于a>b所以k2>k1,所以方程一开始右边减小的比左边增加的快

所以当y=k2*t的时候,减小的最多(之后右边为负数,两边都递增),所以最小值点在y=k2*t,由于误差,我们要在附近几个点找找。


#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
typedef long long ll;
ll myabs(ll a)
{
    return a>0?a:-a;
}
void gcd(ll a,ll b,ll& d,ll& x,ll& y)
{
    if(!b) {d=a;x=1;y=0;}
    else {gcd(b,a%b,d,y,x);y-=x*(a/b);}
}
ll get(ll x,ll y,ll a,ll b,ll d,ll t)
{
    return myabs(x+b/d*t)+myabs(y-a/d*t);
}
int main()
{
    ll a,b,c,d,x,y,t1,t2,ans,x1,y1;
    while(cin>>a>>b>>c&&(a||b||c))
    {
        int f=1;
        if(a<b) {swap(a,b);f=0;}
        gcd(a,b,d,x,y);
        x=x*c/d;y=y*c/d;
        ll t=d*y/a;
        ll mins=0x3f3f3f3f3f3fll;
        for(ll i=t-2;i<=t+2;i++)
        {
            ans=get(x,y,a,b,d,i);
            if(ans<mins)
            {
                mins=ans;
                x1=myabs(x+b/d*i);
                y1=myabs(y-a/d*i);
            }
        }
        if(f) cout<<x1<<" "<<y1<<endl;
        else cout<<y1<<" "<<x1<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TommyTT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值