题目链接:

题意:

有 n 个士兵,每个士兵有两个值 v[i], s[i],分别表示第 i 个士兵的战斗力 v[i] 和他的限制人数 s[i]
限制人数的意思是,如果选择这个士兵 k,那么选择的人数不能超过 s[k]
求选择若干个士兵的最大战斗力。

解法:

首先考虑为了使若干个士兵的最大战斗力最大,我们肯定希望人数尽量多,并且他们的战斗力尽量高。
所以我们首先将士兵按照限制人数 s[i] 从大到小排序,为了使人数最多,我们从左往右取士兵,考虑一下边界情况,由于士兵是按照限制人数从大到小排序的,所以可选的人数一定是当前遍历到的士兵的可选人数,然后如果我们接着加入士兵发现超过了可选人数,我们显然希望将战斗力更低的士兵删掉,所以要选择一个数据结构在维护他,我们重新看一下需要,加入一个元素,将战斗力最低的元素拿出来,并删掉,这不就是优先队列嘛,所以在遍历的同时,有优先队列来维护一下选择的士兵就可以了

代码:

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
#define pi pair<int,int>
using namespace std;
pi a[100005];
auto cmp = [](pi q, pi w) {
    return q.first > w.first;
};
int main()
{
    int n;
    sc("%d", &n);
    for (int i = 0; i < n; i++)
        sc("%d%d", &a[i].first, &a[i].second);
    sort(a, a + n, [](pi q, pi w) {
        return q.second > w.second;
    });
    ll ans = 0, sum = 0;
    int sz = 0;
    priority_queue<pi, vector<pi>, decltype(cmp)>q(cmp);
    for (int i = 0; i < n; i++)
    {
        q.push(pi{ a[i].first,a[i].second });
        sz++;
        sum += a[i].first;
        while (sz > a[i].second)
        {
            sum -= q.top().first;
            q.pop();
            sz--;
        }
        ans = max(ans, sum);
    }
    printf("%lld\n", ans);
}