题目链接:https://ac.nowcoder.com/acm/problem/50439
题意:给你n个士兵,要你组个团,每个士兵都有自己的战斗力和对团中成员最大数量的限制。求这个团的最大战斗力。
思路:如果没有人数限制,那肯定是多多益善。但是有了人数限制,那就要考虑团中人数为多少时,战斗力才会最大。有可能有一个战斗力大于其他所有人之和的士兵,但对人数限制为1.
一开始会想到枚举,将士兵按照人数限制进行从小到大排序,从最小的值开始枚举,设当前限制人数为k,从比k大的人中选,选出里面战斗力最大的k个人就是当限制人数为k时团的最大战斗力。这样复杂度就是n^2的(复杂度可能算的不对~)。于是我们尝试反过来想,从最大的值开始枚举。设最大限制人数为k,也是从比k大的人中选战斗力大的人入团,然后每次k减小,就把最新的所有符合条件的人加入团,在加入团的同时又把战斗力小的士兵剔除,这样答案就出来了。
通过上面的思路,我们很容易想到要用小根堆来维护,因为它的顶部是这个堆中最小的元素,那么就很容易实现剔除这个操作。至此代码也可以写出来了

//author CN.TTDragon
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
const ll maxn=1e5+7;
const double pi=acos(-1);
using namespace std;
//形如“priority_queue<LL> q”是大根堆,下一行写法是小根堆,注意两个>之间一定要有一个空格
priority_queue<ll, vector<ll>, greater<ll> > q;
struct b{
    ll v,s;
    bool operator < (const b &a) const
    {
        return s > a.s;
    }
}b[maxn];
int main()
{
    ll ans=0;
    ll n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>b[i].v>>b[i].s;
        //接收战斗力和人数限制 
    }
    //按人数的限制从大到小排序 
    sort(b,b+n);

    //接下来借助堆来解决这道题目
    ll now=0;
    for(int i=0;i<n;i++)
    {
        now+=b[i].v;
        q.push(b[i].v);

        //前面进来的人对人数的限制肯定不如后来的苛刻 !!!
        while(q.size()>b[i].s)
        {
            //小根堆的特点,堆顶元素肯定最小 
            now-=q.top();
            q.pop();    
        }    

        ans=max(now,ans);    



    } 
    cout<<ans<<endl; 
     return 0;
}