C - シード番号の割り当て / Seed Number Assignment 解説 by admin
gpt-6-astra-medium概要
合計スコアが \(K\) 点以上の参加者だけを取り出し、「合計スコアの降順、参加者番号の昇順」に並べます。その順番でシード番号を割り当て、参加者番号順に出力します。
考察
参加者 \(i\) の合計スコアを \(S_i = A_i + B_i\) とします。本戦に進出できるのは、\(S_i \ge K\) を満たす参加者です。
各参加者について、自分より優先される本戦進出者をすべて調べれば、シード番号を求められます。しかし、この方法では最悪で \(O(N^2)\) 時間かかり、\(N \le 10^5\) では間に合いません。
そこで、本戦進出者を優先順位どおりにソートすることを考えます。ソート後の先頭から \(1, 2, \dots\) と番号を付ければ、それがシード番号になります。
Pythonでは、タプルをソートすると、まず第1要素の昇順に並び、第1要素が同じ場合は第2要素の昇順に並びます。これを利用し、各本戦進出者を次の形で保存します。
(-total, i)
- 合計スコアにマイナスを付けることで、スコアが大きい参加者ほど先に並びます。
- 合計スコアが同じなら、参加者番号に対応する
iが小さい参加者ほど先に並びます。
例えば、\(K = 100\) で、参加者 \(1, 2, 3, 4\) の合計スコアがそれぞれ \(120, 90, 150, 120\) の場合、本戦進出者の優先順位は次のようになります。
| 参加者番号 | 合計スコア | シード番号 |
|---|---|---|
| \(3\) | \(150\) | \(1\) |
| \(1\) | \(120\) | \(2\) |
| \(4\) | \(120\) | \(3\) |
参加者 \(1\) と \(4\) は同点なので、番号の小さい参加者 \(1\) が優先されます。参加者 \(2\) は本戦に進出しないため、答えは \(-1\) です。
なお、出力はシード番号順ではなく参加者番号順です。そのため、割り当てたシード番号は、元の参加者に対応する配列へ記録します。
アルゴリズム
- 長さ \(N\) の配列
answersを、すべて \(-1\) で初期化します。 - 各参加者について、合計スコア
total = a + bを計算します。total >= kなら、(-total, i)をリストqualifiedに追加します。- それ以外の場合は何もしません。
qualifiedを昇順にソートします。- ソート後の先頭からシード番号 \(1, 2, \dots\) を割り当て、対応する
answers[i]に記録します。 answersを先頭から順に、1行に1つずつ出力します。
ソート後の順番は、問題で指定された優先順位と一致しています。したがって、先頭から割り当てた番号は正しいシード番号です。また、本戦に進出しなかった参加者の値は初期値の \(-1\) のままなので、すべての参加者について正しい答えが得られます。
計算量
本戦に進出する参加者数を \(M\) とすると、入力の処理と出力に \(O(N)\)、ソートに \(O(M \log M)\) 時間かかります。\(M \le N\) より、最悪の場合の計算量は次のとおりです。
- 時間計算量: \(O(N \log N)\)
- 空間計算量: \(O(N)\)
実装のポイント
進出条件は「以上」なので、
total >= kとします。合計スコアがちょうど \(K\) 点の参加者も本戦に進出します。コードでは参加者を \(0\) 始まりの添字
iで管理しています。実際の参加者番号は \(i+1\) ですが、大小関係は変わらないため、同点時の比較にもそのまま使えます。enumerate(qualified, 1)を使うと、シード番号を \(1\) から順に取得できます。単に合計スコアの降順にするだけでなく、同点なら参加者番号の昇順という条件も満たす必要があります。
(-total, i)を通常の昇順でソートすれば、両方を同時に実現できます。本戦進出者が一人もいない場合も、
answersがすべて \(-1\) のまま出力されるため、特別な処理は不要です。ソースコード
import sys
def main():
input = sys.stdin.buffer.readline
n, k = map(int, input().split())
qualified = []
answers = [-1] * n
for i in range(n):
a, b = map(int, input().split())
total = a + b
if total >= k:
qualified.append((-total, i))
qualified.sort()
for seed, (_, i) in enumerate(qualified, 1):
answers[i] = seed
sys.stdout.write("\n".join(map(str, answers)))
if __name__ == "__main__":
main()
この解説は gpt-6-astra-medium によって生成されました。