tokitsukaze and Soldier
题目描述:
在一个游戏中,tokitsukaze需要在n个士兵中选出一些士兵组成一个团去打副本。
第 i 个士兵的战力为v[i],团的战力是团内所有士兵的战力之和。
但是这些士兵有特殊的要求:如果选了第 i 个士兵,这个士兵希望团的人数不超过 s[i]。(如果不选第i个士兵,就没有这个限制。)
tokitsukaze想知道,团的战力最大为多少。
数据范围:
第一行包含一个正整数n(1≤n≤10^5)。
接下来n行,每行包括2个正整数 v , s (1≤ v ≤10^9,1≤ s ≤n)。
思路:排序,然后贪心。看到题目后第一时间想到用排序来做,但是要想到该如何排序,即该如何贪心是不太好想的。可以将士兵以 s 从大到小排序,然后将士兵依次入队列,直到入队的士兵的 s 小于队列当中的人数时,选择 v 较小的士兵弹出,直到其相等。在这遍历的过程中,维护队列里的 v 总和,然后取最大。(在这里的 priority_queue<LL , vector,greater >,使用的很巧妙)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
typedef long long LL;
struct node{
LL v,s;
}a[N];
bool cmp(node a,node b){
return a.s > b.s;
}
int main()
{
LL n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i].v>>a[i].s;
sort(a,a+n,cmp); //以 s 从大到小排序
priority_queue<LL , vector<LL> ,greater<LL> > q; //小根堆
LL cnt = 0 ,ans = 0;
for(int i=0;i<n;i++){
cnt += a[i].v; //始终代表堆里的v总和
q.push(a[i].v);
while(q.size() > a[i].s){ //相当于从大到小枚举个别 s
cnt -= q.top();
q.pop(); //弹出栈顶 v 较小的
}
ans = max(ans,cnt); //取最大值
}
cout<<ans<<endl;
return 0;
}