【牛客活动每日一题】tokitsukaze and Soldier【堆】
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; }