ABC236D - Dance

考え方

最大で$2N = 16$人.ペアの組み方は
\begin{aligned}
15!!
&= 15\times 13 \times \cdots \times 3 \times 1 \\
&=2,027,025
\end{aligned}
となる(例えば以下のコード).よって,全探索できる.

ans = 1
x = 15
while x > 0:
  ans *= x
  x -= 2
print(ans)


あとは,どうやってすべての場合を重複なく「列挙するか」,という問題になる.これは,どうやってすべての場合を重複なく「表現するか」がわかればよい.

ペアの組み方を

\begin{aligned}
P = [(1,2), (3,4), ..., (2N-1, 2N) ]
\end{aligned}
のように,ペアを要素としたリストで表すことを考える.

重複なく表記するためには,まず,各ペア$(x, y)$の順序を決めなくてはならない.そこで,常に$x < y$となるように表すことにする.

まだ,$P$内の並び順に不定性が残っている.そこで,$P = [(x_{1}, y_{1}), (x_{2}, y_{2}), ..., (x_{N}, y_{N})]$を$x_{1} < x_{2} < \cdots < x_{N}$となるように,第一要素でソートして表現することにする.

以上で,重複なく$P$を表すことができるようになった.


あとは,$P$の第一要素から順に生成する方法を考えれば良い.つまり,

  1. まだ選んでいない要素の中で最小の要素$x$を選び,
  2. $x$以外の要素$y$を選び,
  3. $(x, y)$を$P$に追加する
となる.

回答例

XORの単位元は$0$.

N = int(input())
A = [list(map(int, input().split())) for _ in range(2 * N - 1)]

ans = 0
def f(cur, score):
  global ans
  if not cur:
    ans = max(ans, score)
    return
  x = cur[0]
  for i in range(1, len(cur)):
    y = cur[i]
    nxt = cur[1:i] + cur[i + 1:]
    f(nxt, score ^ A[x - 1][y - 1 - x])
  return
    
f([i + 1 for i in range(2 * N)], 0)
print(ans)

【参考】【解説 実況】ABC236 AからD【かつっぱ】 - YouTube