UVALive_6170_Esspe-Peasee(求解不定方程)

题型:数论


题意:求解不定方程ax+by=c,要求x+y最小且x、y非负,如果多个x+y,x尽量小。


分析:

扩展欧几里得求解方程,注意格式问题。


代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>

#define LL long long
using namespace std;

/**
不定方程的求解思路:
扩展gcd求出ax+by=gcd(a,b)=d的一组特解(x0,y0)
如果c%d!=0,无解

a0 = a/d
b0 = b/d
x0 = x0*(c/d)
y0 = y0*(c/d)
通解:
       x=x0+k*b0
       y=y0-k*a0

如果要求|x|+|y|最小,有-b0<y<b0
*/

/**求解ax+by=c,x为非负数的最小解,且如果x和y非负,x+y最小*/
class IndefiniteEquation {
    typedef LL DataType;
    DataType a,b,c;
    DataType x,y;
    /**gcd*/
    DataType gcd(DataType A,DataType B) {
        return B?gcd(B,A%B):A;
    }
    /**扩展gcd*/
    DataType ext_gcd(DataType A,DataType B,DataType &x0,DataType &y0) {
        DataType t,ret;
        if(!B) {
            x = 1;
            y = 0;
            return A;
        }
        ret = ext_gcd(B,A%B,x0,y0);
        t = x0;
        x0 = y0;
        y0 = t-A/B*y0;
        return ret;
    }
public:
    void init(DataType aa,DataType bb,DataType cc) {
        a = aa;
        b = bb;
        c = cc;
    }
    /**false无解,true有解*/
    bool solve() {
        if(c==0) {
            x = y = 0;
            return true;
        }
        if(a==0 && b==0) {
            return false;
        }
        if(a==0) {
            if(c%b) {
                return false;
            } else {
                x = 0;
                y = c/b;
                return true;
            }
        }
        if(b==0) {
            if(c%a) {
                return false;
            } else {
                x = c/a;
                y = 0;
                return true;
            }
        }
        DataType d = gcd(a,b);
        if(c%d) return false;
        a /= d;
        b /= d;
        c /= d;
        d = ext_gcd(a,b,x,y);
        DataType t = c%b;
        x %= b;
        x = (x*t)%b;
        x = (x+b)%b;
        y = (c-(x*a))/b;
        return true;
    }
    /**解x*/
    DataType x0(){
        return x;
    }
    /**解y*/
    DataType y0(){
        return y;
    }

}ts;

void no(){
    puts("Unquibable!");
}
void out(LL x,LL y){
    printf("%lld foom",x);
    if(x!=1) printf("s");
    printf(" and %lld foob",y);
    if(y!=1) printf("s");
    puts(" for a twob!");
}

int main() {
    LL a,b,c;
    while(~scanf("%lld%lld%lld",&a,&b,&c)){
        if(!(a|b|c)) break;
        ts.init(a,b,c);
        bool flag = ts.solve();

        if(flag){
            if(ts.y0()<0) no();
            else{
                out(ts.x0(),ts.y0());
            }
        }
        else{
            no();
        }

    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值