本题是一个可后悔的贪心,首先从简单来看,如果单纯根据战力选择可能会因为人数现在而没有达到最优,如果根据人数限制选择,可能会出现极端战力导致错误。
但如果两个条件其中之一我们已知的话求解起来就比较简单了,如果我们已知人数限制,那么只需要在所有人数限制超过这个的人里面选最好的几个就行了。这看起来很像二分答案的思路,
但因为战力总和相对于人数并不单调,无法采用二分的方式。在这里采用从人数大到小枚举的方式,因为人数在从大到小,所以原来人数限制大的哪些士兵是不需要退出的,因为他们本来人数限制就可以容忍。但因为会有新的士兵进来,所以可能会将战力底的老士兵给挤掉,所以在这里建立一个小根堆来维护最小的战力。然后每一个人数下都有一个最优的战力,取最大值即可。
#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;
}