公式
B - 奨学金選考 / Scholarship Selection 解説 by admin
Qwen3-Coder-480B概要
各学生の成績が与えられ、すべての科目で基準点以上を満たした学生の中から、成績の合計が高い順に \(K\) 人(同点含む)を選抜する問題。
考察
この問題では、まず「すべての科目で基準点以上」を満たす学生(基準通過者)だけを対象とします。これは各学生ごとに全科目をチェックすることで判定できます。
次に、基準通過者の合計点を計算し、高い順に並べ替えます。ただし、同点の場合は学生番号の昇順という条件があります。そのため、ソートキーを (-合計点, 学生番号) とすることで、自然に条件を満たせます。
さらに注意すべきは、上位 \(K\) 人を選ぶときに、\(K\) 番目の得点と同じ得点を持つ学生は全員選ばれるという点です。例えば、\(K=3\) で上位3人の得点が [100, 90, 90] なら、90点の人は全員選ばれます。そのため、\(K\) 番目の得点を取得し、それ以上の得点を持つ学生をすべて抽出する必要があります。
素朴な方法として、最初から全員をソートして上位 \(K\) 人を取るだけでは、同点処理がうまくいかない可能性があるため、得点比較を行う必要があります。
また、制約より \(M \leq 10\) なので、各学生の基準通過判定や合計点の計算は高速に行えます。
アルゴリズム
- 各学生について、すべての科目で基準点以上か判定し、基準通過者をリストアップする。
- 基準通過者について、全科目の合計点を計算し、
(合計点, 学生番号)の形で保存。 - このリストを以下のルールでソート:
- 合計点の降順(高い順)
- 合計点が同じなら学生番号の昇順
- ソート後、上位 \(K\) 人のうち最も低い得点を取得。
- その得点以上の学生をすべて選抜(同点含む)。
- 選抜された学生番号を昇順に出力。
計算量
- 時間計算量: \(O(N \cdot M + N \log N)\)
- 各学生の基準通過判定に \(O(M)\)、それが \(N\) 人分 → \(O(N \cdot M)\)
- ソートに \(O(N \log N)\)
- 空間計算量: \(O(N + M)\)
- 基準点配列 \(T\) と、基準通過者のリストに必要な領域
実装のポイント
- 同点処理をするために、\(K\) 番目の得点を明確に取得し、それ以上の得点を持つ学生を全員選ぶ必要がある。
- ソートキーを
(-score, id)とすることで、得点降順・番号昇順を同時に実現できる。 - 入力を高速に読み込むことで、\(N\) が最大 \(10^5\) でも間に合うようにしている。
## ソースコード
```python
import sys
# 入力の読み込み
input = sys.stdin.read
data = input().split()
idx = 0
N = int(data[idx])
idx += 1
M = int(data[idx])
idx += 1
K = int(data[idx])
idx += 1
# 基準点の読み込み
T = list(map(int, data[idx:idx+M]))
idx += M
# 学生データの読み込み
students = []
for i in range(N):
scores = list(map(int, data[idx:idx+M]))
idx += M
# 基準通過判定
passed = all(scores[j] >= T[j] for j in range(M))
if passed:
total = sum(scores)
students.append((total, i + 1)) # (合計点, 学生番号)
# 合計点の降順、学生番号の昇順でソート
students.sort(key=lambda x: (-x[0], x[1]))
# 上位K人の合計点を取得(K番目と同じ点数の人も含む)
if not students:
exit()
# K番目の合計点を取得
k_th_score = students[min(K, len(students)) - 1][0]
# K番目と同じ点数以上の学生をすべて選ぶ
recipients = [student[1] for student in students if student[0] >= k_th_score]
# 昇順にソートして出力
recipients.sort()
for num in recipients:
print(num)
この解説は qwen3-coder-480b によって生成されました。
投稿日時:
最終更新: