题解:#2088.「CSP-J 2020」直播获奖 审核通过

zswzh 2025-10-14 21:01:22 6

要做这题,首先得了解对顶堆

对顶堆,它由两部分组成,上和下,而上面那部分是一个小根堆,下面则是大根堆

了解了对根队就来讲讲思路


思路

两个堆:

大根堆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;
}
{{ vote && vote.total.up }}