B - 奨学金選考 / Scholarship Selection 解説 by admin
GPT 5.2 High概要
各学生が「全科目で最低点以上か」を判定して基準通過者を集め、通過者の中から合計点が高い順に上位 \(K\) 位(同点は全員)までの学生番号を昇順で出力する問題です。
考察
まず「基準通過者」の条件は 全科目で \(S_{i,j} \ge T_j\) なので、学生ごとに \(M\) 科目を見れば判定できます(\(M \le 10\) なので十分軽い)。
次に、受給者の決め方が少し注意点です:
- 基準通過者を合計点の降順に並べたとき
- 「上位 \(K\) 人」だが、第 \(K\) 位と同点の学生がいれば全員採用
→ つまり「合計点が第 \(K\) 位の合計点以上の通過者は全員採用」です。
素朴に「基準通過者を全部ソートして、先頭 \(K\) 人だけ取る」だと、同点処理を忘れて WA になります。
例:合計点が [100, 90, 80, 80, 70]、\(K=3\) のとき、第3位は80点で同点がいるので、採用は80点の2人を含めて 4人 になります。
この同点処理は、「第 \(K\) 位の合計点(境界値)を求め、その値以上を全員採用」とすると簡潔に処理できます。
アルゴリズム
- 入力を読み込む。
- 各学生 \(i\) について
- 全科目で \(S_{i,j} \ge T_j\) かを判定する(1つでも下回れば失格)。
- 同時に合計点 \(sum_i=\sum_{j=1}^{M} S_{i,j}\) を計算する。
- 基準を満たす学生だけ
(sum_i, i)を配列qualifiedに入れる。
qualifiedの人数を \(Q\) とする。- \(Q=0\) なら何も出力しない。
- \(Q \le K\) なら、基準通過者全員を採用(番号を昇順にして出力)。
- \(Q > K\) なら、
qualifiedを合計点の降順でソート- 第 \(K\) 位(0-indexで
K-1)の合計点kth_sumを取得 - 合計点が
kth_sum以上の学生を全員集め、学生番号を昇順で出力
計算量
- 時間計算量:
基準判定・合計計算が \(O(NM)\)、通過者数を \(Q\) としてソートが \(O(Q \log Q)\)
よって全体で \(O(NM + Q \log Q)\)(\(M \le 10\) なので十分高速) - 空間計算量: \(O(Q)\)(基準通過者の
(合計点, 番号)を保持)
実装のポイント
\(N \le 10^5\) なので、Pythonでは
sys.stdin.buffer.read()でまとめて読み取ると安定して高速です。同点処理は「第 \(K\) 位の合計点
kth_sumを求め、total >= kth_sumを全員採用」とすると漏れがありません。出力は「学生番号の昇順」指定なので、採用者の番号だけ最後に
sorted()してから改行区切りで出力します。基準通過者が 0 人のときは何も出力しない仕様なので、早めに
returnします。ソースコード
import sys
def main():
data = list(map(int, sys.stdin.buffer.read().split()))
it = iter(data)
N = next(it)
M = next(it)
K = next(it)
T = [next(it) for _ in range(M)]
qualified = []
for i in range(1, N + 1):
total = 0
ok = True
for j in range(M):
s = next(it)
if s < T[j]:
ok = False
total += s
if ok:
qualified.append((total, i))
qn = len(qualified)
if qn == 0:
return
if qn <= K:
ans = sorted(idx for _, idx in qualified)
else:
qualified.sort(key=lambda x: x[0], reverse=True)
kth_sum = qualified[K - 1][0]
ans = sorted(idx for total, idx in qualified if total >= kth_sum)
sys.stdout.write("\n".join(map(str, ans)))
if __name__ == "__main__":
main()
この解説は gpt-5.2-high によって生成されました。
投稿日時:
最終更新: