一堆有时限的资源,每天消耗一个——“先到期先用”是这类贪心问题的通用原则。
题目
果园里有
你每天最多吃一个苹果,也可以在拥有苹果的日子里不吃。求最多能吃多少个苹果。
输入格式
- 第一行一个整数
; - 第二行
个整数 ; - 第三行
个整数 。
输出格式
- 输出一个整数:最多能吃到的苹果数。
样例
样例输入
input
4
1 2 3 5
2 5 3 2样例输出
output
6样例解释
- 第
天:长出的 个苹果(第 天可吃),吃掉,累计 ; - 第
天:长出 个(第 天可吃),吃 个,累计 ; - 第
天:长出 个(第 天可吃),优先吃先到期的,累计 ; - 第
天:长出 个(第 天可吃),吃 个,累计 ; - 第
天:吃第 天的剩余,累计 ;第 天:吃第 天的剩余,累计 ; - 第
天后所有苹果腐烂,答案 。
提示
用一个以“最后可食用日”为关键字的小根堆:每天把当天新长的苹果入堆,弹出已腐烂的,再吃堆顶。
题解
点击查看题解
核心思路
贪心原则:每天优先吃最后可食用日最早的苹果(最紧急的先消耗)。
用一个小根堆维护当前持有的苹果,关键字是“最后可食用日”:
- 第
天,把 入堆( 时); - 弹出所有最后可食用日
的批次(已腐烂); - 若堆非空,从堆顶批次吃一个(剩余为
则整体弹出),答案加 。
第
复杂度分析
- 时间复杂度:
- 空间复杂度:
点击查看参考代码
cpp
#include <functional>
#include <iostream>
#include <queue>
#include <utility>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n), d(n);
for (auto& x : a) cin >> x;
for (auto& x : d) cin >> x;
// 小根堆: (最后可食用日, 该批次剩余个数)
priority_queue<pair<int, long long>,
vector<pair<int, long long>>, greater<>> pq;
long long eaten = 0;
for (int day = 1; day <= n; ++day) {
if (a[day - 1] > 0) pq.push({day + d[day - 1] - 1, (long long)a[day - 1]});
while (!pq.empty() && pq.top().first < day) pq.pop(); // 清理腐烂
if (!pq.empty()) { // 吃最紧急的一批
auto [exp, rem] = pq.top();
pq.pop();
if (--rem > 0) pq.push({exp, rem});
++eaten;
}
}
// n 天之后继续吃剩下的
long long day = (long long)n + 1;
while (!pq.empty()) {
while (!pq.empty() && pq.top().first < day) pq.pop();
if (pq.empty()) break;
auto [exp, rem] = pq.top();
pq.pop();
if (--rem > 0) pq.push({exp, rem});
++eaten;
++day;
}
cout << eaten << '\n';
return 0;
}本地运行与提交
powershell
pnpm lab:run -- labs/chapter-05/exercise/E-05-12-eat-apples