[ABC263F] Tournament
Problem Statement
$2^N$ people, numbered $1$ to $2^N$, will participate in a rock-paper-scissors tournament.
The tournament proceeds as follows:
- The participants are arranged in a row in the order Person $1$, Person $2$, $\ldots$, Person $2^N$ from left to right.
- Let $2M$ be the current length of the row. For each $i\ (1\leq i \leq M)$, the $(2i-1)$-th and $(2i)$-th persons from the left play a game against each other. Then, the $M$ losers are removed from the row. This process is repeated $N$ times.
Here, if Person $i$ wins exactly $j$ games, they receive $C_{i,j}$ yen (Japanese currency). A person winning zero games receives nothing. Find the maximum possible total amount of money received by the $2^N$ people if the results of all games can be manipulated freely.
Constraints
- $1 \leq N \leq 16$
- $1 \leq C_{i,j} \leq 10^9$
- All values in input are integers.
Input
Input is given from Standard Input in the following format:
$N$ $C_{1,1}$ $C_{1,2}$ $\ldots$ $C_{1,N}$ $C_{2,1}$ $C_{2,2}$ $\ldots$ $C_{2,N}$ $\vdots$ $C_{2^N,1}$ $C_{2^N,2}$ $\ldots$ $C_{2^N,N}$
Output
Print the answer.
Sample Input 1
2 2 5 6 5 2 1 7 9
Sample Output 1
15
The initial row of the people is $(1,2,3,4)$.
If Person $2$ wins the game against Person $1$, and Person $4$ wins the game against Person $3$, the row becomes $(2,4)$.
Then, if Person $4$ wins the game against Person $2$, the row becomes $(4)$, and the tournament ends.
Here, Person $2$ wins exactly $1$ game, and Person $4$ wins exactly $2$ games, so they receive $0+6+0+9=15$ yen in total, which is the maximum possible sum.
Sample Input 2
3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
我们不能知道这棵树每个节点是哪位参赛者,但我们可以通过这棵树的形式来做 dp。
满二叉树我们可以用线段树类似的方式给每个节点编号。易得,如果一个叶子节点编号为 \(x\),那么他代表第 \(x-2^n\) 号参赛者。一个参赛者赢得场数要从他输的那场的前面算。
定义 \(dp_{i,j}\) 为现在到了第 \(i\) 号节点,这名参赛者参加了 \(i\) 次比赛。转移时我们枚举是左子树的参赛者赢了还是右子树的参赛者赢了就好了。加个记忆化。
想到了代码非常好写。但之前完全没往这棵树上想过。
#include<bits/stdc++.h>
using namespace std;
const int N=17;
int n,c[1<<N][N];
long long dp[1<<N][N];
long long dfs(int x,int y)
{
if(x>=(1<<n))
return c[x^(1<<n)][y];
if(~dp[x][y])
return dp[x][y];
return dp[x][y]=max(dfs(x<<1,y+1)+dfs(x<<1|1,0),dfs(x<<1|1,y+1)+dfs(x<<1,0));
}
int main()
{
memset(dp,-1,sizeof(dp));
scanf("%d",&n);
for(int i=0;i<(1<<n);i++)
for(int j=1;j<=n;j++)
scanf("%d",c[i]+j);
printf("%lld",dfs(1,0));
return 0;
}