[GESP202506 五级] 奖品兑换

视频讲解:GESP202506 五级 奖品兑换-信息学奥赛GESP等级考试真题解析

一、原题

题目背景

为了保证只有时间复杂度正确的代码能够通过本题,时限下降为 400 毫秒。

题目描述

班主任给上课专心听讲、认真完成作业的同学们分别发放了若干张课堂优秀券和作业优秀券。同学们可以使用这两种券找班主任兑换奖品。具体来说,可以使用 a 张课堂优秀券和 b 张作业优秀券兑换一份奖品,或者使用 b 张课堂优秀券和 a 张作业优秀券兑换一份奖品。

现在小 A 有 n 张课堂优秀券和 m 张作业优秀券,他最多能兑换多少份奖品呢?

输入格式

第一行,两个正整数 n,m,分别表示小 A 持有的课堂优秀券和作业优秀券的数量。

第二行,两个正整数 a,b,表示兑换一份奖品所需的两种券的数量。

输出格式

输出共一行,一个整数,表示最多能兑换的奖品份数。

输入输出样例

输入 #1

bash 复制代码
8 8
2 1

输出 #1

bash 复制代码
5

输入 #2

bash 复制代码
314159 2653589
27 1828

输出 #2

bash 复制代码
1599

说明/提示

对于 60% 的测试点,保证 1 ≤ a,b ≤ 100,1 ≤ n,m ≤ 500。

对于所有测试点,保证 1 ≤ a,b ≤ ,1 ≤ n,m ≤

二、做题思路

1)尝试暴力模拟(考场只能60分)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main() {
	//确定课堂券n,作业券m
	int n,m;
	cin>>n>>m;
	//确定兑换条件a,b
	int 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)保证 大对大,小对小

cpp 复制代码
#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)计算二分范围

cpp 复制代码
int left = min(n / a, m / b);
int right = (n + m) / (a + b);

2.3)二分模板

cpp 复制代码
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)判断答案标准

cpp 复制代码
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)保证 大对大,小对小

三、答案

cpp 复制代码
#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;	
}
相关推荐
alphaTao4 小时前
LeetCode 每日一题 2026/8/24-2026/8/30
python·算法·leetcode
Interview Aid1125 小时前
TikTok OA 四题分享|半小时内 AC,题目基本都是实现题
java·开发语言·算法·面试·职场和发展
顶点多余14 小时前
那些在算法中适合巩固的知识点---1
java·前端·算法
AI情绪识别开源15 小时前
检信 ALLEMOTION OS 加密打包可执行程序 — 全面测试报告版本: v1.3功能测试 / 性能测试 /
开发语言·数据结构·人工智能·功能测试
罗西的思考15 小时前
【Agentic RL / 强化学习框架】Molt 设计解读
人工智能·算法·机器学习
hahaha601616 小时前
HLS高层次综合设计技巧--C++类和模板
图像处理·人工智能·算法·计算机视觉
多弗朗皮卡丘17 小时前
算法详解4:买卖股票的最佳时机系列(上)
算法
维克兜率天19 小时前
【维克】动量指标家族:RSI、ROC、CCI、Momentum全面解析
python·算法
AI情绪识别开源20 小时前
检信 AI 智能推广平台(代号:JX-Promote)
人工智能·算法·erlang
老当益壮梁奶奶20 小时前
Linux软件编程学习笔记(八):进程间通信详解(1)
linux·c语言·笔记·学习·算法