tokitsukaze and Soldier
思路
这题的话,我觉得用堆来实现最为方便,这题的数据量为,那么配合堆,时间复杂度是
,时间上是ok的。
大概思路就是,首先在读入数据的时候,就把最大s和最小s保存下来,然后从大到小遍历,求每一个s对应选取的最大战斗力和,如果要选取s人,那么就把s[i]>=s的人放进堆里面去,然后限制堆的容量是s,并动态求堆的和,在放入堆的时候,sum += v[i],如果堆的容量已经大于s,就pop,并sum -= q.pop();
这题我觉得最核心的是,假如s[i] < s[i+1],那么在求s[i+1]能选取的最大战斗力和之后,再计算s[i]能选取的最大战斗力和是可以在s[i+1]的基础上进行增删。
代码
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll maxn = 1e6+10;
double eps = 1e-8;
int N;
ll res;
struct node{
int v,s;
bool operator < (const node &o)const{
return s<o.s;
}
}arr[maxn];
priority_queue<int,vector<int>,greater<int> > q;
int main(){
cin>>N;
int l = 1e9,r = 0; //记录最小s和最大s
for(int i = 0;i<N;i++){
scanf("%d %d",&arr[i].v,&arr[i].s);
l = min(l,arr[i].s),r = max(r,arr[i].s);
}
sort(arr,arr+N);
ll sum = 0,tail = N-1;//我是倒着循环的
for(int i = r;i>=l;i--){ //倒着循环我觉得方便些
while(arr[tail].s >= i){ //只让堆存i个以内的个数,并动态求和
q.push(arr[tail].v);
sum += arr[tail].v;
while(q.size() > i){
int t = q.top();q.pop();
sum -= t;
}
tail--;
}
res = max(res,sum);
}
cout<<res<<endl;
return 0;
}
京公网安备 11010502036488号