Poj P2142 The Balance___exgcd

题目大意:

a,bcnosolution 给 出 一 个 天 平 ( 天 平 左 右 两 边 都 可 以 放 砝 码 ) 与 重 量 为 a , b 的 两 种 砝 码 。 让 你 求 出 一 种 方 案 称 出 重 为 c 的 物 品 , 如 有 多 种 方 案 , 请 输 出 两 种 砝 码 需 要 数 量 的 总 和 最 小 的 方 案 , 无 解 输 出 n o s o l u t i o n

多组数据
1a,b10000 1 ≤ a , b ≤ 10000
c50000 c ≤ 50000

分析:

很明显可以转换成一个等式,
ax+by=c a x + b y = c
那么就可以愉悦的用 exgcd e x g c d 求出一个通解 x0,y0 x 0 , y 0
其中显示一个为正数一个为负数,
而题目要求的是一个最小的 |x|+|y| | x | + | y |
我们可以发现,
Gcd=gcd(a,b) G c d = g c d ( a , b )
任意一个解 x,y x , y 必定满足
x=x0+b/Gcdi x = x 0 + b / G c d ∗ i y=y0a/Gcdi y = y 0 − a / G c d ∗ i
那么 |x|+|y| | x | + | y | 就可以转化成
|x0+b/Gcdi|+|y0a/Gcdi| | x 0 + b / G c d ∗ i | + | y 0 − a / G c d ∗ i |
我们钦定 a>b a > b ,那么显然
|y0a/Gcdi | y 0 − a / G c d ∗ i |的变化幅度比 |x0+b/Gcdi| | x 0 + b / G c d ∗ i | 大,
y0a/Gcdi=0 y 0 − a / G c d ∗ i = 0
|x0+b/Gcdi|+|y0a/Gcdi| | x 0 + b / G c d ∗ i | + | y 0 − a / G c d ∗ i | = =
|x0+b/Gcdi|+0=
|x0+b/Gcdi| | x 0 + b / G c d ∗ i | 这时候最小,
因为可能这时候的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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值