【洛谷 P7072】[CSP-J2020] 直播获奖 题解(优先队列+对顶堆)

183 阅读3分钟

[CSP-J2020] 直播获奖

题目描述

NOI2130 即将举行。为了增加观赏性,CCF 决定逐一评出每个选手的成绩,并直播即时的获奖分数线。本次竞赛的获奖率为 w%w\%,即当前排名前 w%w\% 的选手的最低成绩就是即时的分数线。

更具体地,若当前已评出了 pp 个选手的成绩,则当前计划获奖人数为 max(1,p×w%)\max(1, \lfloor p \times w \%\rfloor),其中 ww 是获奖百分比,x\lfloor x \rfloor 表示对 xx 向下取整,max(x,y)\max(x,y) 表示 xxyy 中较大的数。如有选手成绩相同,则所有成绩并列的选手都能获奖,因此实际获奖人数可能比计划中多。

作为评测组的技术人员,请你帮 CCF 写一个直播程序。

输入格式

第一行有两个整数 n,wn, w。分别代表选手总数与获奖率。
第二行有 nn 个整数,依次代表逐一评出的选手成绩。

输出格式

只有一行,包含 nn 个非负整数,依次代表选手成绩逐一评出后,即时的获奖分数线。相邻两个整数间用一个空格分隔。

样例 #1

样例输入 #1

10 60
200 300 400 500 600 600 0 300 200 100

样例输出 #1

200 300 400 400 400 500 400 400 300 300

样例 #2

样例输入 #2

10 30
100 100 600 100 100 100 100 100 100 100

样例输出 #2

100 100 600 600 600 600 100 100 100 100

提示

样例 1 解释


数据规模与约定

各测试点的 nn 如下表:

测试点编号n=n=
131 \sim 31010
464 \sim 6500500
7107 \sim 1020002000
111711 \sim 1710410^4
182018 \sim 2010510^5

对于所有测试点,每个选手的成绩均为不超过 600600 的非负整数,获奖百分比 ww 是一个正整数且 1w991 \le w \le 99


提示

在计算计划获奖人数时,如用浮点类型的变量(如 C/C++ 中的 floatdouble,Pascal 中的 realdoubleextended 等)存储获奖比例 w%w\%,则计算 5×60%5 \times 60\% 时的结果可能为 3.0000013.000001,也可能为 2.9999992.999999,向下取整后的结果不确定。因此,建议仅使用整型变量,以计算出准确值。


思路

成绩根据其大小将其插入到两个堆之一。如果贡献值大于或等于最小堆的顶部元素,那么就将其插入到最小堆中,否则插入到最大堆中。这样做的目的是确保最小堆的所有元素都大于或等于最大堆的所有元素,从而方便后续的处理。

接下来,根据当前的用户数量和设定的获奖比例计算出应该有多少用户可以获奖。然后通过调整两个堆的大小,确保最小堆的大小等于获奖用户的数量。具体来说,如果最小堆的大小大于获奖用户的数量,那么将最小堆的顶部元素移动到最大堆中;如果最小堆的大小小于获奖用户的数量,那么将最大堆的顶部元素移动到最小堆中。这样,最小堆的顶部元素就是当前的最低获奖门槛。

最后,输出当前的最低获奖门槛。这个过程会在每次有新的贡献时重复,从而实时更新获奖名单。


AC代码

#include <algorithm>
#include <iostream>
#include <queue>
#define AUTHOR "HEX9CF"
using namespace std;

priority_queue<int> hmax;
priority_queue<int, vector<int>, greater<int>> hmin;

int main() {
	int n, w;
	cin >> n >> w;
	for (int p = 1; p <= n; p++) {
		int s;
		cin >> s;
		// 插入元素
		if (!hmin.empty() && s >= hmin.top()) {
			hmin.push(s);
		} else {
			hmax.push(s);
		}
		int num = max(1, (int)(p * w * 0.01));
		// cout << s << " " << num << endl;
		// 维护对顶堆
		while (hmin.size() > num) {
			int tmp = hmin.top();
			hmin.pop();
			hmax.push(tmp);
		}
		while (hmin.size() < num) {
			int tmp = hmax.top();
			hmax.pop();
			hmin.push(tmp);
		}
		cout << hmin.top() << " ";
	}
	return 0;
}