Summer Vacation(贪心,优先队列)
题意
有\(N\)个任务。如果你完成第\(i\)个任务,从做的那天起\(A_i\)天后,你将会获得\(B_i\)的奖励(比如第\(1\)天开始做,\(A_i = 3\),那么第\(3\)天将会获得\(B_i\)的奖励)。
你每天可以选择其中一个任务做,但是任务不能重复完成。
问从今天起\(M\)天后,你最多可以获得多少奖励?
题目链接:https://atcoder.jp/contests/abc137/tasks/abc137_d
数据范围
\(1 \leq N, M \leq 10^5\)
\(1 \leq A_i \leq 10^5\)
\(1 \leq B_i \leq 10^4\)
思路
考虑\(M\)天之前的第\(i(1 \leq i \leq M)\)天,我们只能选择\(A_j \leq i\)的工作。
对于这种问题,先考虑较紧的限制会使得问题变简单。
当\(i = 1\)时,我们只能选择\(A_j = 1\)的工作来做,因为只能选择\(1\)个工作,因此需要选择奖励最多的那个。
当\(i = 2\)时,我们可以选择\(A_j \leq 2\)的工作来做,因此我们可以选择\(A_j \leq 2\)的工作中奖励最多的那个(除去\(i=1\)所选择的那个)。
我们可以进一步抽象这个问题,我们每次需要向一个集合中加入一些数字,并取出其中的最大值。因此,可以使用优先队列去做。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 100010;
int n, k;
vector<int> jobs[N];
int main()
{
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i ++) {
int a, b;
scanf("%d%d", &a, &b);
jobs[a].push_back(b);
}
int ans = 0;
priority_queue<int> que;
for(int i = 1; i <= k; i ++) {
for(auto p : jobs[i]) que.push(p);
if(que.size()) {
ans += que.top();
que.pop();
}
}
printf("%d\n", ans);
return 0;
}