ABC263-Fに苦戦しました。Pythonで解きました。

abc263F問題に超絶苦戦したので、コメントアウトを多めに書きこみながら丁寧にACしました。言語はPythonです。

誰かのお役に少しでも立てれば幸いです。

コード

"""

n = int(input())
C = [[0] + list(map(int, input().split())) for _ in range(1 << n)]

# dp[i][j] :  ノード iにおいて、人jが勝ち上がっているときの、これまでノード iの子ノードで負けた人が貰うお金の合計の最大値
dp = [[0] * (1 << n) for _ in range(n + 1)]

# 誰かしらがwin_num回勝った場合を考える
for win_num in range(1, n + 1):
    # 例えば誰かが2回勝った場合(win_num = 2)を考える
    # その場合{0, 1, 2, 3}の小トーナメント, {4, 5, 6, 7}の小トーナメント, {8, 9, 10, 11} ...を考えれば良い
    # よってiにはそれぞれの小トーナメントの最も左の人(0, 4, 8, ...)を格納していく
    for i in range(0, 1 << n, 1 << win_num):
        # 小トーナメントの左半分の人をjに格納する. 
        # {0, 1, 2, 3}のトーナメントなら, 0, 1を格納する
        # 0, 1が2回勝たなかった場合(すなわち, 0が1回だけ勝つ場合と, 1が1回だけ勝つ場合)にもらえるお金の最大値を求める
        left_max = 0
        for j in range(i, i + (1 << (win_num - 1))):
            left_max = max(left_max, dp[win_num - 1][j] + C[j][win_num - 1])
        # 小トーナメントの右半分の人をjに格納する
        # {0, 1, 2, 3}のトーナメントなら, 2, 3を格納する
        # 人jが2回勝つ場合の、負けた人がもらえるお金の最大値を求める
        # 人jがもらえるお金は格納しないことに注意
        for j in range(i + (1 << (win_num - 1)), i + (1 << win_num)):
            dp[win_num][j] = left_max + dp[win_num - 1][j]

        # 上の2つのfor文と左右を反転させて同じことをする
        right_max = 0
        for j in range(i + (1 << (win_num - 1)), i + (1 << win_num)):
            right_max = max(right_max, dp[win_num - 1][j] + C[j][win_num - 1])
        for j in range(i, i + (1 << (win_num - 1))):
            dp[win_num][j] = right_max + dp[win_num - 1][j]

# dp[n][j]に格納しているのはjがn回勝った時に負けた人が貰うお金の合計の最大値
# よって, 最後にjがn回勝った時にもらえるお金を考慮して最大を取る必要がある
ans = 0
for j in range(1 << n):
    ans = max(ans, dp[n][j] + C[j][n])
print(ans)

参考: https://atcoder.jp/contests/abc263/editorial/4550