题目描述
在一个游戏中,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)。
输出描述:
输出一个正整数,表示团的最大战力。
示例1
输入
2
1 2
2 2
输出
3
示例2
输入
3
1 3
2 3
100 1
输出
100
解题思路
这个题我们很容易想到,要么按照战力值排序,要么按照每个士兵希望团的人数进行排序。
假设我们按照战力值进行排序,那么在寻找答案遍历过程中,我们不能很好知道当前这个组团状态下最小的组团人数。那么我们就只能按照希望团的人数进行排序,但是在保证这个的前提下,战力值大的往前排。
那么我们这时候只需要不断的压入一个士兵的战力,同时看看优先队列的长度是否超过当前这个士兵的期望了,如果是的话就把最小战力的士兵给弹出。然后每次我们更新一下最终答案。
解题代码
这个题可以有两种姿势来解题。
结构体法
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
const int maxn=4e5+10;
struct Node{
ll s,v;
}node[maxn];
bool cmp(Node a,Node b){
if(a.s==b.s) return a.v>b.v;
return a.s>b.s;
}
priority_queue<ll ,vector<ll>,greater<ll> >q;
int main(){
int i,j,n;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%lld%lld",&node[i].v,&node[i].s);
}
sort(node,node+n,cmp);
ll ans=0,temp=0;
for(i=0;i<n;i++){
temp+=node[i].v;
q.push(node[i].v);
while(q.size()>node[i].s){
ll te=q.top();
q.pop();
temp-=te;
}
if(temp>ans) ans=temp;
}
printf("%lld\n",ans);
return 0;
}
pair法
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
const int maxn=4e5+10;
typedef pair<ll,ll> PII;
struct cmp{
bool operator ()(PII a,PII b){
return a.first>b.first;
}
};
priority_queue<PII ,vector<PII>,cmp>q;
bool cmp(PII a,PII b){
if(a.second== b.second) return a.first>b.first;
return a.second > b.second;
}
PII a[maxn];
int main(){
int i,j,n;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%lld%lld",&a[i].first,&a[i].second);
}
sort(a,a+n,cmp);
ll ans=0,temp=0;
for(i=0;i<n;i++){
temp+=a[i].first;
q.push(a[i]);
while(q.size()>a[i].second){
ll te=q.top().first;
q.pop();
temp-=te;
}
if(temp>ans) ans=temp;
}
printf("%lld\n",ans);
return 0;
}