P2949 [USACO09OPEN] Work Scheduling G
题意
现在有\(n\)个工作,每个工作对应一个到期的时限\(D_i\)和一个完成工作可获得的报酬\(P_i\)。
每完成一个工作需要耗费\(1\)的单位时间。
现在你需要考虑如何安排工作才可以使获得的报酬最大。并输出最大的报酬。
胡诌
这是一道带需要可以反悔的贪心题。
首先我们尽量完成多的任务。这样价值可能会比较大。
所以我们按照时间来排序。
用一个小根堆来维护我们已完成的工作中的可获得的报酬的最小值。
如果我们当前枚举到的工作时限已经过了,我们跟最小值比较一下。如果目前工作可获得的收益大的话说明我们完成这个工作可获得的效益更高。这个就是反悔的过程。
否则直接累加即可。
证明的话因为花费的时间都是一样的,那么我们把价值大留下来肯定更优。
这样枚举到到最后一定是最大值。
因为每完成一个工作需要的时间都是\(1\),所以小根堆中节点的数量就是已经花费的时间。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e5+10;
int n, ans;
pair<int,int> a[maxn];
signed main(){
scanf("%lld", &n);
for(int i = 1; i <= n; i ++) scanf("%lld%lld", &a[i].first, &a[i].second);
sort(a+1, a+n+1);
priority_queue<int, vector<int>, greater<int> > q;
for(int i = 1; i <= n; i ++){
if(a[i].first <= q.size()){
if(a[i].second > q.top()){
ans -= q.top();
ans += a[i].second;
q.pop();
q.push(a[i].second);
}
}else q.push(a[i].second), ans += a[i].second;
}
printf("%lld\n", ans);
return 0;
}