用树状数组维护 0..600 的成绩频率,并通过第 k 小查询在线求当前获奖分数线。
OJ: luogu
题目 ID: P7072
难度:普及-
标签:树状数组计数模拟python
日期: 2026-06-19 00:26
题意
成绩依次公布。公布第 seen 个成绩后,取排名前 max(1, seen*w//100) 人中的最低成绩作为当前分数线。
思路
成绩只在 0..600,用树状数组保存每个分数的出现次数。若当前有 winners 人获奖,分数线就是升序第 seen-winners+1 个成绩。树状数组的倍增查找可以在
全程只用整数计算获奖人数,避免浮点向下取整误差。
Python 知识
enumerate(data, 1)直接得到当前已公布人数。int.bit_length()取得树状数组倍增搜索的最高二进制步长。- 分数范围虽小,Fenwick 写法比每轮倒扫 601 个桶更适合 Python 的循环性能。
代码
python
import sys
data = iter(map(int, sys.stdin.buffer.read().split()))
n, percentage = next(data), next(data)
tree = [0] * 602
def add(index):
index += 1
while index < len(tree):
tree[index] += 1
index += index & -index
def kth(k):
index = 0
step = 1 << (len(tree).bit_length() - 1)
while step:
next_index = index + step
if next_index < len(tree) and tree[next_index] < k:
index = next_index
k -= tree[next_index]
step >>= 1
return index
answer = []
for seen, score in enumerate(data, 1):
add(score)
winners = max(1, seen * percentage // 100)
answer.append(kth(seen - winners + 1))
print(*answer)复杂度
时间复杂度
总结
动态分数线本质是频率数组上的第
