题目意思

给定n个人,每个人有武力值和忍耐人数上线,需要最终组成一个团去计算最终的最大武力值之和。

解题思路

很容易想到,枚举每个人的s值,求解在这个s值下选取适当的人的最大武力值是多少,最终的最大答案就是题目要求得答案。
上面是一种思路,但是极其难实现,想想为啥,每个人的s值不同,选定一个人的s值,再选s-1个人中,可能改变最小的s值。。。
我们又找到s大的与s小的对比,我们要注意得是s小的人,因为如果选定了这个人是在答案中,先达到饱和的一定是s小的。
那么我们想对s进行一次降序排序,从大到小枚举s。那么我们又如何去按照这个s值求解答案呢?
我们知道如果选定了一个k,表示团队最大人数。那么我们就可以在s[i]大于等于k中选取武力值最大的k个人。
k根据题目可以取到每个人的s值。
那么要如何记录满足当前人s得情况下,得武力值最大呢,没错选择小根堆(优先队列),我们把武力值小的人放在堆顶。
每次如果当前堆中元素大于了这个人的s,那么我们就把堆顶元素删除,对应武力值之和去掉堆顶元素。
最后对每个人的s值求解一遍,最终留下最符合要去的最大的就是答案。

https://ac.nowcoder.com/acm/contest/view-submission?submissionId=43627838&returnHomeType=1&uid=919749006

Code

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;

inline int read() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}

const int N = 1e5 + 7;
struct Node {
    ll w;
    int s;
    bool operator<(const Node& a)const {
        return s > a.s;
    }
}a[N];
priority_queue<ll, vector<ll>, greater<ll> > pq;
// 小根堆,如果不加vector只后内容默认为大根堆,大值在堆顶,注意> >有空格

int main() {
    int n = read();
    for (int i = 1; i <= n; ++i)
        a[i].w = read(), a[i].s = read();

    //按照s的降序排序
    sort(a + 1, a + 1 + n);

    // tmp是当前这个人的s前提下最大,ans是最终答案
    ll ans = 0, tmp = 0;
    for (int i = 1; i <= n; ++i) {
        tmp += a[i].w;
        pq.push(a[i].w);

        // 满足当前这个人的s情况下,最大
        // 也就是k从大到小的取值,取遍所有k,求得最大答案
        while (pq.size() > a[i].s) {
            tmp -= pq.top(); pq.pop();
        }

        //更新答案
        ans = max(ans, tmp);
    }
    printf("%lld\n", ans);
    return 0;
}