题目意思
给定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值求解一遍,最终留下最符合要去的最大的就是答案。
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;
} 
京公网安备 11010502036488号