CSP-J 2020 T2 直播获奖(洛谷P7072
CSP-J 2020 T2 直播获奖
这道题一开始看很容易想出一个简单的做法,每一次输入完一个分数就从大到小排一下序,然后输出第\(\max(1,\lfloor p*w\% \rfloor)\)个数即可,但时间复杂度为\(O(n^2 \log n)\),有\(n=10^5\)这种恐怖数据的话\(O(n^2 \log n)\)的时间复杂度肯定是无法AC这道题的。
那咋办呢,让我们研究一下数据范围,发现每个选手的成绩均为不超过600的非负整数,那这个范围不是可以用桶排吗?瞬间就变简单了有没有。那么怎么用桶排打出这道题呢?因为第一名是最高分,所以我们从大到小进行遍历,每次让分数线的名次减去取得这个分数的人数,直到分数线的名次小于等于0为止。
这里我用了一个优化,记录最低分和最高分,在这个范围内遍历而不是从600遍历到0,大概能优化几十倍左右。
代码
#include <iostream>
#include <cmath>
using namespace std;
int t[605];
int main()
{
int n,s,p,mi,ma,w;
cin>>n>>w;
for(int i=1;i<=n;++i){
cin>>s;
//记录最低分和最高分
mi=min(mi,s);
ma=max(ma,s);
//桶排
t[s]++;
//计算分数线是第几名
p=max(1,i*w/100);
for(int j=ma;j>=mi;--j){
//在桶内进行遍历,找到分数线
p-=t[j];
//如果找到了就输出
if(p<=0){
cout<<j<<' ';
break;
}
}
}
return 0;
}