题解:P1040 [NOIP 2003 提高组] 加分二叉树
原题传送门
思路
首先二叉树的中序遍历具有左孩子遍历序列一定在根结点的左边,右孩子遍历序列一定在根结点的右边的性质。
因此我们假设一颗二叉树的根为
所以我们令
代码
#include<bits/stdc++.h>
#define int long long
#define inf 0x7f7f7f7f
using namespace std;
const int maxn = 1e6 + 100;
inline int read() {
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int dp[50][50] , n , val[50] , root[50][50];
inline int dfs(int l , int r) {
if(l == r) {
root[l][r] = r;
dp[l][r] = val[l];
return dp[l][r];
}
if(l > r) {
root[l][r] = 0;
dp[l][r] = 1;
return dp[l][r];
}
if(dp[l][r]) return dp[l][r];
for(int i = l; i <= r; i++) {
int tl = dfs(l , i - 1) , tr = dfs(i + 1 , r);
if(tl * tr + val[i] > dp[l][r]) dp[l][r] = tl * tr + val[i] , root[l][r] = i;
}
return dp[l][r];
}
inline void bl(int l , int r) {
if(!root[l][r]) return ;
cout << root[l][r] << " ";
bl(l , root[l][r] - 1);
bl(root[l][r] + 1 , r);
}
signed main() {
n = read();
for(int i = 1; i <= n; i++) val[i] = read();
cout << dfs(1 , n) << endl;
bl(1 , n);
return 0;
}