A - トーナメント敗退ラウンド / Tournament Elimination Round 解説 by admin
GPT 5.4 High概要
トーナメントの組み合わせは完全に固定されており、しかも「強い方が必ず勝つ」ので、ラウンドごとにそのまま勝者を残していけばよいです。
各試合の敗者に「何ラウンド目で負けたか」を記録し、最後まで残った 1 人の答えを \(0\) にします。
考察
この問題の重要な点は次の 2 つです。
- 対戦結果は強さを 1 回比較するだけで決まる
- トーナメント表の並び順は最初から最後まで固定されている
重要な観察
ラウンド \(1\) では
- 選手 \(1\) vs 選手 \(2\)
- 選手 \(3\) vs 選手 \(4\)
- …
と戦います。
そして次のラウンドでは、その勝者たちが
- 第 1 試合の勝者 vs 第 2 試合の勝者
- 第 3 試合の勝者 vs 第 4 試合の勝者
- …
という形で戦います。
つまり、そのラウンドに残っている選手をトーナメント順に並べて持っておけば、隣り合う 2 人ずつを戦わせるだけで次のラウンドを作れるということです。
素朴な考え方
各選手について
- どの相手と当たるか
- どのラウンドで自分より強い選手に当たるか
を個別に考えることもできますが、これは人ごとに調べると複雑で、実装も重くなりがちです。
どう解決するか
実際には、トーナメント全体の試合数は全部で \(N-1\) 試合しかありません。
なので、全試合を 1 回ずつシミュレーションすれば十分です。
各ラウンドで
- 今残っている選手の列
currentを見る - 2 人ずつ比較する
- 負けた選手の答えをそのラウンド番号にする
- 勝った選手だけを
nxtに入れる
これを 1 人になるまで繰り返せば答えが求まります。
例
例えば \(N=8\) で、今のラウンドの生存者が
[0, 1, 2, 3, 4, 5, 6, 7]
(内部では 0-indexed)だとします。
ラウンド \(1\) では
0vs12vs34vs56vs7
を戦わせ、勝者だけを順番に nxt に入れます。
すると nxt は次のラウンドの並びそのものになります。
この「順番を保ったまま勝者を並べる」ことがポイントです。
アルゴリズム
current = [0, 1, 2, ..., N-1]を用意する
- ここには「今のラウンドに残っている選手の番号」を順番通りに入れる
ansを長さ \(N\) の配列で \(0\) 初期化する
- 優勝者は最後まで更新されないので、そのまま \(0\) になる
round_num = 1とするcurrentの長さが 1 になるまで以下を繰り返す- 空の配列
nxtを作る currentを 2 つずつ見る- 選手
a,bの強さS[a],S[b]を比較する - 強い方を
nxtに追加する - 負けた方の
ansにround_numを記録する - ラウンド終了後、
current = nxtにする round_num += 1
- 空の配列
ansを出力する
計算量
- 時間計算量: \(O(N)\)
- 空間計算量: \(O(N)\)
時間計算量が \(O(N)\) である理由
各試合は 1 回しか処理しません。
シングルエリミネーションの試合数は全部で
\(N/2 + N/4 + \cdots + 1 = N-1\)
なので、全体で \(O(N)\) です。
実装のポイント
currentには強さではなく選手の添字を入れる
こうすると- 強さ比較は
S[a] > S[b] - 答えの記録は
ans[a],ans[b]
- 強さ比較は
のように簡単に書けます。
- 勝者を必ず元の順番のまま nxt に入れることが重要です。
順番が崩れると、次ラウンドの対戦相手が変わってしまいます。
- このコードでは ans を最初に全部 \(0\) で初期化しているので、最後まで負けない優勝者は自動的に \(0\) のままになります。
- array('I') を使うことで、大きな入力でもメモリを節約できます。
ソースコード
import sys
from array import array
def main():
input = sys.stdin.buffer.readline
N = int(input())
S = array('I', map(int, input().split()))
ans = array('I', [0]) * N
current = list(range(N))
round_num = 1
while len(current) > 1:
nxt = []
append = nxt.append
for i in range(0, len(current), 2):
a = current[i]
b = current[i + 1]
if S[a] > S[b]:
ans[b] = round_num
append(a)
else:
ans[a] = round_num
append(b)
current = nxt
round_num += 1
sys.stdout.write(' '.join(map(str, ans)))
if __name__ == "__main__":
main()
この解説は gpt-5.4-high によって生成されました。
投稿日時:
最終更新: