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;
}
posted @ 2022-06-15 15:13  pbc的成长之路  阅读(21)  评论(0编辑  收藏  举报