[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;	
}
相关推荐
Gorway19 小时前
解析残差网络 (ResNet)
算法
拖拉斯旋风20 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect20 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript
灵感__idea1 天前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
Wect2 天前
LeetCode 130. 被围绕的区域:两种解法详解(BFS/DFS)
前端·算法·typescript
NAGNIP2 天前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
颜酱3 天前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub3 天前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub3 天前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub3 天前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉