题面
在一个游戏中,需要在n个士兵中选出一些士兵组成一个团,第i个士兵的战力为v[i],团的战力是团内所有士兵的战力之和。但是这些士兵有特殊的要求:如果选了第i个士兵,这个士兵希望团的人数不超过s[i]。(如果不选第i个士兵,就没有这个限制。) 问团的战力最大为多少。
数据范围: n ( 1 ≤ n ≤ 1 0 5 , 1 ≤ v ≤ 1 0 9 , 1 ≤ s ≤ n ) n(1≤n≤10^5, 1≤v≤10^9,1≤s≤n) n(1≤n≤105,1≤v≤109,1≤s≤n)
分析
若是某个方案选取的其中一个士兵,其限制为
s
i
s_i
si, 那么能达成的最佳方案就是在所有 s 值大于等于
s
i
s_i
si的士兵中再挑选
s
i
−
1
s_i - 1
si−1个士兵。
可以将士兵按照s值从大到小排序,依次将士兵插入优先队列中(小顶堆),若是有限队列的元素个数大于当前士兵的s值,那么就一直将队首元素去掉,这样子的队列维护即是上述最佳方案的实现,记录维护过程中的最大值即为所求。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
struct node
{
int s, v;
bool operator<(const node& m1)
{
return s > m1.s;
}
}pro[maxn];
priority_queue<int, vector<int>, greater<int> > que;
int n;
ll ans, cur;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d %d", &pro[i].v, &pro[i].s);
sort(pro + 1, pro + 1 + n);
for(int i = 1; i <= n; i++)
{
que.push(pro[i].v);
cur += pro[i].v;
while(que.size() > pro[i].s)
{
cur -= que.top();
que.pop();
}
ans = max(ans, cur);
}
printf("%lld\n", ans);
}