本题是一个可后悔的贪心,首先从简单来看,如果单纯根据战力选择可能会因为人数现在而没有达到最优,如果根据人数限制选择,可能会出现极端战力导致错误。
但如果两个条件其中之一我们已知的话求解起来就比较简单了,如果我们已知人数限制,那么只需要在所有人数限制超过这个的人里面选最好的几个就行了。这看起来很像二分答案的思路,
但因为战力总和相对于人数并不单调,无法采用二分的方式。在这里采用从人数大到小枚举的方式,因为人数在从大到小,所以原来人数限制大的哪些士兵是不需要退出的,因为他们本来人数限制就可以容忍。但因为会有新的士兵进来,所以可能会将战力底的老士兵给挤掉,所以在这里建立一个小根堆来维护最小的战力。然后每一个人数下都有一个最优的战力,取最大值即可。
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int maxn = 1e5+10; struct Node { int v;//战力 int s;//人数 } node[maxn]; priority_queue<int, vector<int>, greater<int> > pq; bool comp(Node n1, Node n2) { return n1.s>n2.s; } int main() { int n; cin>>n; for (int i=0;i<n;i++) { cin>>node[i].v; cin>>node[i].s; } sort(node, node+n, comp); ll ans = 0, Ans; for (int i=0;i<n;i++) { int xz = node[i].s; if ((pq.size()+1)<=xz) { pq.push(node[i].v); ans+=node[i].v; } else if ((pq.size()+1)>xz) { if (pq.top()<node[i].v) { ans-=pq.top(); pq.pop(); pq.push(node[i].v); ans+=node[i].v; } } while (pq.size()>xz) { ans -= pq.top(); pq.pop(); } Ans = max(ans, Ans); } cout<<Ans; return 0; }