Poj P2142 The Balance___exgcd

题目大意:

a,bcnosolution

多组数据
1a,b10000
c50000

分析:

很明显可以转换成一个等式,
ax+by=c
那么就可以愉悦的用exgcd求出一个通解x0,y0
其中显示一个为正数一个为负数,
而题目要求的是一个最小的|x|+|y|
我们可以发现,
Gcd=gcd(a,b)
任意一个解x,y必定满足
x=x0+b/Gcdiy=y0a/Gcdi
那么|x|+|y| 就可以转化成
|x0+b/Gcdi|+|y0a/Gcdi|
我们钦定a>b,那么显然
|y0a/Gcdi|的变化幅度比|x0+b/Gcdi|大,
y0a/Gcdi=0
|x0+b/Gcdi|+|y0a/Gcdi|=
|x0+b/Gcdi|+0=
|x0+b/Gcdi|这时候最小,
因为可能这时候的i为实数,
所以我们在i的附近找即可
坑,一开始在oj上直接用abs,CE两次。。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define INF 0x7fffff 

using namespace std;

typedef long long LL;

LL num(LL x) {
    if (x < 0) return -x;
    return x;
}

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

int main() {
    LL a, b, c, x, y;
    while (~scanf("%I64d %I64d %I64d", &a, &b, &c)) {
           if (!a && !b && !c) break;
           bool flag = 0;
           if (a < b) {
               flag = 1;
               swap(a,b);
           }
           LL Gcd = exgcd(a, b, x, y);
           if (c % Gcd != 0) {
               printf("no solution\n");
               continue;
           }
           x *= (c / Gcd);
           y *= (c / Gcd);
           LL t = (y * Gcd) / a;
           LL ansx = INF, ansy = INF;
           for (LL i = t - 5; i <= t + 5; i++) {
                if (num(x + b / Gcd * i) + num(y - a / Gcd * i) < ansx + ansy) {
                    ansx = num(x + b / Gcd * i);
                    ansy = num(y - a / Gcd * i);
                }
           }
        if (!flag) printf("%I64d %I64d\n", ansx, ansy);
              else printf("%I64d %I64d\n", ansy, ansx);
    }
    return 0;
}
阅读更多
版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/Gx_Man_VIP/article/details/80455982
个人分类: C++ gcd&exgcd
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭