[GESP202506 五级] 奖品兑换
视频讲解:[GESP202506 五级] 奖品兑换-信息学奥赛GESP等级考试真题解析
一、原题
题目背景
为了保证只有时间复杂度正确的代码能够通过本题,时限下降为 400 毫秒。
题目描述
班主任给上课专心听讲、认真完成作业的同学们分别发放了若干张课堂优秀券和作业优秀券。同学们可以使用这两种券找班主任兑换奖品。具体来说,可以使用 a 张课堂优秀券和 b 张作业优秀券兑换一份奖品,或者使用 b 张课堂优秀券和 a 张作业优秀券兑换一份奖品。
现在小 A 有 n 张课堂优秀券和 m 张作业优秀券,他最多能兑换多少份奖品呢?
输入格式
第一行,两个正整数 n,m,分别表示小 A 持有的课堂优秀券和作业优秀券的数量。
第二行,两个正整数 a,b,表示兑换一份奖品所需的两种券的数量。
输出格式
输出共一行,一个整数,表示最多能兑换的奖品份数。
输入输出样例
输入 #1
8 8
2 1
输出 #1
5
输入 #2
314159 2653589
27 1828
输出 #2
1599
说明/提示
对于 60% 的测试点,保证 1 ≤ a,b ≤ 100,1 ≤ n,m ≤ 500。
对于所有测试点,保证 1 ≤ a,b ≤ ,1 ≤ n,m ≤
。
二、做题思路
1)尝试暴力模拟(考场只能60分)
#include<bits/stdc++.h>
using namespace std;
int main() {//确定课堂券n,作业券mint n,m;cin>>n>>m;//确定兑换条件a,bint a,b;cin>>a>>b;//保证a>b if(a<b) swap(a,b); //模拟贪心过程 int ans=0;while(true){//保证n>m,大的兑换大的 if(n<m) swap(n,m);n-=a;m-=b;//兑换不了,退出 if(n<0||m<=0) break;//兑换次数+1 ans++;}cout<<ans;
}
2)官方二分答案实现
2.1)保证 大对大,小对小

#include<bits/stdc++.h>
using namespace std;
int n, m, a, b;
int main() {cin >> n >> m >> a >> b;if (a > b) swap(a, b);if (n > m) swap(n, m);
}
2.2)计算二分范围

int left = min(n / a, m / b);
int right = (n + m) / (a + b);
2.3)二分模板
int mid = 0, ans;
while (left <= right) {mid = (left + right) / 2;if ( is(mid) ) {left = mid + 1;ans = mid;} else {right = mid - 1;}
}
cout << ans;
2.4)判断答案标准

bool is(int x) {//计算余额 int bank = n - x * a;int bro = m - x * b;//计算续弥补的损失 int diffp = b - a;int money = ceil(-bro * 1.0 / diffp) * diffp;//无法弥补,直接退出 if ( bank < 0) return false;if ( bro < 0 && bank < money ) return false;//能弥补返回true return true;}
2.2)保证 大对大,小对小
三、答案
#include<bits/stdc++.h>
using namespace std;
int n, m, a, b;
bool is(int x) {//计算余额 int bank = n - x * a;int bro = m - x * b;//计算续弥补的损失 int diffp = b - a;int money = ceil(-bro * 1.0 / diffp) * diffp;//无法弥补,直接退出 if ( bank < 0) return false;if ( bro < 0 && bank < money ) return false;//能弥补返回true return true;}
int main() {cin >> n >> m >> a >> b;if (a > b) swap(a, b);if (n > m) swap(n, m);int left = min(n / a, m / b);int right = (n + m) / (a + b);int mid = 0, ans;while (left <= right) {mid = (left + right) / 2;//cout<<mid<<" "<<left<<" "<<right<<endl; if ( is(mid) ) {left = mid + 1;ans = mid;} else {right = mid - 1;}}cout << ans;
}

