1899:【17NOIP提高组】小凯的疑惑

【题目描述】

小凯手中有两种面值的金币,两种面值均为正整数且彼此互素。每种金币小凯都有无数个。在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的。现在小凯想知道在无法准确支付的物品中,最贵的价值是多少金币?注意:输入数据保证存在小凯无法准确支付的商品。

【输入】

输入数据仅一行,包含两个正整数 aa 和 bb,它们之间用一个空格隔开,表示小凯手中金币的面值。

【输出】

输出文件仅一行,一个正整数 NN,表示不找零的情况下,小凯用手中的金币不能准确支付的最贵的物品的价值。

【输入样例】

3 7

【输出样例】

11

【提示】

【样例说明】

小凯手中有面值为33和77的金币无数个,在不找零的前提下无法准确支付价值为 12458111、2、4、5、8、11的物品,其中最贵的物品价值为1111。

1111贵的物品都能买到,比如:

12=3×4+7×0

13=3×2+7×1

14=3×0+7×2

15=3×5+7×0

【数据范围】

对于 30% 的数据:1≤a,b≤501≤a,b≤50;

对于 60% 的数据: 1≤a,b≤10,0001≤a,b≤10,000;

对于 100% 的数据:1≤a,b≤1,000,000,0001≤a,b≤1,000,000,000。

样例数据下载

题解

首先,我们发现这两个数是互质的,并且有无限个。很容易想到不定方程 ax + by = gcd(a, b)ax+by=gcd(a,b) ,其中 gcd(a, b) = 1gcd(a,b)=1 。

然后我们考虑,对于所有可行的能被 aa 和 bb 表示出来的数 kk ,都存在 x \geq 0, y \geq 0,ax + by = kx≥0,y≥0,ax+by=k

现在我们要构造的是最大的不合法的数,显然,这个数 + 1+1 一定是一个合法的数,转化成了求最大的减一后不合法的数

由于这个数 kk 一定是合法的,所以满足性质

\exists x \geq 0, \exists y \geq 0,ax + by = k∃x≥0,∃y≥0,ax+by=k

那么如果 k-1k−1 合法,那么 k - 1k−1 可以表示成

a \left ( x - x' \right ) + b \left ( y - y' \right ) = ka(xx′)+b(yy′)=k

a \left ( x - x'' \right ) + b \left ( y - y'' \right ) = ka(xx′′)+b(yy′′)=k

其中 x',y'x′,y′ 表示 ax + by = 1ax+by=1 的 xx 最小且非负的整数解; x'',y''x′′,y′′ 表示 ax + by = 1ax+by=1 的 yy 最小且非负的整数解。

那么现在只需要让 x - x'< 0xx′<0 并且 y - y'' < 0yy′′<0 即可

那么最后的最大的减一后不合法的数就是

a \left ( x' - 1 \right ) + b \left ( y'' - 1 \right )a(x′−1)+b(y′′−1)

那么最后的答案就是

a \left ( x' - 1 \right ) + b \left ( y'' - 1 \right ) - 1a(x′−1)+b(y′′−1)−1

证明:

首先充分性成立。

然后证明必要性:若a \left ( x' - 1 \right ) + b \left ( y'' - 1 \right )a(x′−1)+b(y′′−1)不是最大的减一后不合法的数,那么一定存在一个更大的数,显然该数的 aa 的系数大于 x' - 1x′−1 或 bb 的系数大于 y'' - 1y′′−1 (如果都小于等于,那么该数不会比当前数大)。显然,减一后仍然是合法的。所以必要性成立。

综上, a \left ( x' - 1 \right ) + b \left ( y'' - 1 \right ) - 1a(x′−1)+b(y′′−1)−1 是最大的不合法的数。

最后代码如下:

#include<bits/stdc++.h>

using namespace std;

int main() {

long long i, n;

cin >> i >> n;

cout << i*n - i - n;

return 0;

}

or

#include <iostream>

#include <cstring>

#include <cstdio>

#include <algorithm>

#include <cmath>

using namespace std;

typedef long long ll;

ll gcd(ll a, ll b) {

return b == 0 ? a : gcd(b, a % b);

}

void ex_gcd(ll a, ll b, ll &x, ll &y) {

if (b == 0) {

x = 1, y = 0;

return;

}

ex_gcd(b, a % b, y, x);

y -= (a / b) * x;

}

ll a, b;

int main() {

cin >> a >> b;

if (a > b) swap(a, b);

ll x, y;

ex_gcd(a, b, x, y);

if (x > 0) {

swap(a, b);

swap(x, y);

}

ll tmp = (-x) / b;

x = x + tmp * b;

y = y - tmp * a;

while (x < 0) x = x + b, y = y - a;

while (x > 0) x = x - b, y = y + a;

ll ans;

ll xx2 = x + b;

ans = a * (xx2 - 1) + b * (y - 1);

cout << ans - 1 << endl;

return 0;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值