题解:P13013 [GESP202506 五级] 奖品兑换
no_response · · 题解
题目传送门
故事
先吐槽一句,在考试的时候,编译器给我卡爆了,花了半小时才做完了,当时满分了。
然后我信心满满的提交了题解,第二天题解通道给我关了,我愣住了,然后下午发现原来数据加强了,还升黄了,给我打回来了,我只能重构新算法。
题意
小 A 有
小 A 可以花
我们需要求出最多可以换取多少个奖品。
分析
考试时就一眼杀了,这题考贪心。数据加强后现在题目要用二分了。暴力解法我就不讲了,只能拿部分分,就讲一下能满分的二分算法。
先要确保
- 二分会有起始的
left 和right 。 - 循环一般用
while,条件一般为while(left <= right)。 - 在循环内部要用
middle 来求left 和right 的中间值,即middle = (left + right) / 2。 - 以上代码可优化成
middle = left + (right - left) / 2,这样可以确保不会溢出。 - 通过一个函数的返回值,去修改
left 或right 的值,即left = middle + 1或right = middle - 1。 - 二分因为每次减少一半的范围,所以时间复杂度为
O(\log n) 。
输入加二分框架:
int n, m, a, b, v;
cin >> n >> m >> a >> b;
if (n < m) {
swap(n, m);
}
if (a < b) {
swap(a, b);
}
v = a - b;
int left = 0, right = n;
int ans = 0;
while (left <= right) {
int middle = left + (right - left) / 2;
if (check(middle) == 1) {
ans = max(ans, middle);
left = middle + 1;
} else {
right = middle - 1;
}
}
接下来就是写
把
注意
此题因 #define int long long。
AC CODE
#include <bits/stdc++.h>
#define int long long //不开80分
using namespace std;
int n, m, a, b, v;
bool check(int middle) { //求解
int x = a * middle, y = b * middle; //按当前比例分配的总量
if (x > n) { //若x超过上限n时
int k = (x - n + v - 1) / v; //需要转换的量
x -= k * v, y += k * v; //等比例转换
}
if (x <= n && y <= m) { //最后判断
return 1;
}
return 0;
}
signed main() {
cin >> n >> m >> a >> b;
if (n < m) { //保证n>=m
swap(n, m);
}
if (a < b) { //保证a>=b
swap(a, b);
}
v = a - b; //修改
int left = 0, right = n; //二分l,r
int ans = 0;
while (left <= right) { //二分条件
int middle = left + (right - left) / 2; //二分mid
if (check(middle) == 1) { //两种情况
ans = max(ans, middle); //修改
left = middle + 1; //缩减范围
} else {
right = middle - 1; //缩减范围
}
}
cout << ans; //输出代码
return 0;
}