题解 P7072 【直播获奖(民间数据)】
yukimainyan · · 题解
好题,好题!(结果看了别人的题解还发现我可能想得太复杂了……)
设当前有i个人评出成绩时获奖分数线为第k人的分数,因为需要输出每个k所对应的值,所以需要加入一个数就自动排序,很自然就能想到优先队列
那这个问题就变成了对每个i求最大k个数的最小值,建立一个小根堆,如果此时堆里的数据还不够k个,则加入一个新数据;如果已经够了k个,则要考虑一下需不需要进行数据替换。
那么新数据的选择是一个很关键的问题。一开始我下意识地将新读入的第i个数据直接加入小根堆,但手推了一遍样例1之后发现,有可能之前已经被踢出小根堆的数据会比当前新读入的第i个数据来得要优,此时如果选择新读入的第i个数据加入小根堆的话就会出错。
考虑到这一点,可以建立一个大根堆,用于保存当前不是前k大的数,新输入的数据直接加入大根堆。如果当前用于统计前k大的数的小根堆里,元素的个数还不足k个时,直接取大根堆的堆顶加入小根堆即可;如果此时元素的个数已经够了k个,则要考虑新加入的数据是否会产生影响,即比较大根堆和小根堆的堆顶,如果此时小根堆的堆顶<大根堆的堆顶,则交换。对于两个相邻的i来说,k的最大变化量只能为1,所以只处理堆顶元素就好。
还有个坑就是确定k值,谁能想到我因为向下取整连着三种做法都wa连个点
代码如下
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
priority_queue <int,vector<int>,greater<int> > a;
priority_queue <int,vector<int>,less<int> > b;
int n,p;
int main(){
cin >> n >> p;
for (int i=1;i<=n;i++){
int tot=p*i/100;
tot=max(1,tot);
//cout << tot << endl;
int temp;
cin >> temp;
b.push(temp);
if (a.size()<tot){
a.push(b.top());
b.pop();
}
else{
if (a.top()<b.top()){
a.push(b.top());
b.pop();
b.push(a.top());
a.pop();
}
}
cout << a.top() << " ";
}
return 0;
}
请不要直接复制粘贴哦(
另外还看到了桶排序的做法,本来以为会超时,是我想太多了()