C - 対戦カードの組み合わせ / Matchup Card Combinations Editorial by admin
Claude 4.6 Opus (Thinking)概要
同じ競技にエントリーしていて、かつ異なるチームに所属する2人の選手の組み合わせ数を求める問題です。「同じ競技のペア数」から「同じ競技かつ同じチームのペア数」を引く、という補集合の考え方で効率的に解けます。
考察
素朴なアプローチの問題点
最も単純な方法は、\(N\) 人の選手からすべての2人組 \(\frac{N(N-1)}{2}\) 通りを列挙し、各ペアについて「同じ競技か?」「異なるチームか?」を判定することです。しかし、\(N\) が最大 \(2 \times 10^5\) のため、ペア数は最大約 \(2 \times 10^{10}\) 通りとなり、TLE(時間超過)になります。
重要な気づき:補集合で考える
対戦が成立する条件は「同じ競技 かつ 異なるチーム」です。これを直接数えるのは難しいので、次のように分解します。
\[\text{対戦成立ペア数} = \text{同じ競技のペア数} - \text{同じ競技かつ同じチームのペア数}\]
つまり、まず同じ競技に属するペアをすべて数え、そこから同じチーム同士のペア(対戦できない)を引けばよいのです。
具体例
例えば、競技1に5人いるとします。この5人から2人を選ぶペア数は \(\binom{5}{2} = 10\) 通りです。
そのうち、競技1でチームAに3人、チームBに2人いるなら、同じチームのペア数は \(\binom{3}{2} + \binom{2}{2} = 3 + 1 = 4\) 通りです。
よって、競技1で対戦が成立するペア数は \(10 - 4 = 6\) 通りです。
アルゴリズム
- 競技ごとの人数を数える:
sport_count[p]に、競技番号 \(p\) にエントリーしている選手数を格納します。 - (競技, チーム)ごとの人数を数える:
sport_team_count[(p, q)]に、競技 \(p\) かつチーム \(q\) に属する選手数を格納します。 - 同じ競技のペア数を合計する: 各競技について \(\binom{n}{2} = \frac{n(n-1)}{2}\) を計算し、合計します。
- 同じ競技かつ同じチームのペア数を引く: 各(競技, チーム)の組について \(\binom{c}{2} = \frac{c(c-1)}{2}\) を計算し、合計から引きます。
最終的な値が答えです。
計算量
- 時間計算量: \(O(N)\) — 各選手を1回ずつ処理し、Counter の各エントリを1回ずつ走査するだけです。
- 空間計算量: \(O(N)\) — Counter に格納するエントリ数は最大 \(N\) 個です。
実装のポイント
Counter(辞書)を活用: Pythonの
collections.Counterを使うことで、競技ごと・(競技, チーム)ごとの人数集計を簡潔に書けます。組み合わせ数の公式: \(n\) 人から2人を選ぶ組み合わせ数 \(\binom{n}{2} = \frac{n(n-1)}{2}\) は頻出公式です。整数除算
//を使って正確に計算できます。引き算で求める発想: 「条件Aかつ条件B」を直接数えるのが難しい場合、「条件Aの全体」から「条件Aかつ条件Bでない部分」を引くテクニックは競技プログラミングで非常によく使います。
ソースコード
from collections import Counter
def main():
import sys
input = sys.stdin.readline
N = int(input())
players = []
for _ in range(N):
p, q = map(int, input().split())
players.append((p, q))
# Count players per sport
sport_count = Counter()
# Count players per (sport, team) pair
sport_team_count = Counter()
for p, q in players:
sport_count[p] += 1
sport_team_count[(p, q)] += 1
# For each sport, total pairs = C(n, 2)
# Same-team pairs in that sport = sum of C(c, 2) for each team
# Valid pairs = total pairs - same-team pairs
answer = 0
for sport, n in sport_count.items():
answer += n * (n - 1) // 2
for (sport, team), c in sport_team_count.items():
answer -= c * (c - 1) // 2
print(answer)
main()
この解説は claude4.6opus-thinking によって生成されました。
posted:
last update: