要做这题,首先得了解对顶堆
对顶堆,它由两部分组成,上和下,而上面那部分是一个小根堆,下面则是大根堆
了解了对根队就来讲讲思路
思路
两个堆:
大根堆x:存储候选元素,堆顶是最大的候选元素
小根堆y:存储当前获奖元素,堆顶是最小的获奖元素
核心逻辑:
对于每一个新输入的元素,先放入候选堆x
计算当前应该获奖的人数cnt
如果获奖堆y的元素数量不足cnt,就从候选堆x中取最大元素放入获奖堆y
如果候选堆x的最大元素大于获奖堆y的最小元素,说明有更优秀的候选者,需要交换它们
此时获奖堆y的堆顶就是当前第cnt名的成绩,直接输出即可
由于本题数据小,所以这题可以用桶排,但如果数据再大一点就会超时,而优先队列此时就是一个更优解
AC code
#include <iostream>
#include <vector> //用于小根堆的定义
#include <queue>
using namespace std;
//候选堆(大根堆)
priority_queue<int> x;
//获奖堆(小根堆)
priority_queue<int, vector<int>, greater<int>> y;
int main() {
freopen("live.in", "r", stdin);
freopen("live.out", "w", stdout);
int n, w, t;
cin >> n >> w;
for (int i = 1; i <= n; i++) {
cin >> t;
int cnt = max(1, i * w / 100); //计划获奖人数
x.push(t);
//如果获奖人数不够cnt,就一直移走候选堆的堆顶放在获奖堆那
while (y.size() < cnt && x.size()) {
y.push(x.top());
x.pop();
}
//如果候选堆堆顶元素大于获奖堆的堆顶元素
//,那么就把候选堆的堆顶移走,放到获奖堆里,再把获奖堆的堆顶放在候选堆里面
if (x.size() && y.size() && x.top() > y.top()) {
//处理移动
int num = y.top();
y.pop();
y.push(x.top());
x.pop();
x.push(num);
}
//输出获奖堆的堆顶元素
cout << y.top() << " ";
}
return 0;
}