题面
分析
因为要输出先序遍历,因此我们只需要存某个区间的根节点是谁即可;
然后按二叉树的先序遍历去dfs
即可;
又因为要字典序最大,只需要维护最左边且最大的值即可;
维护最大值的话,很容易想到枚举断点,将断点看为根节点,去划分左右子树;
f [ l ] [ r ] = f [ l ] [ k − 1 ] + f [ k + 1 ] [ r ] , k 为 根 节 点 f[l][r] = f[l][k-1]+f[k+1][r],k为根节点 f[l][r]=f[l][k−1]+f[k+1][r],k为根节点;
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 30 + 10;
int f[N][N],g[N][N],n,w[N];//维护区间最大值与根节点
void dfs(int l,int r){
if(l > r) return;
int root = g[l][r];
cout << root << ' ';
dfs(l,root-1);
dfs(root+1,r);
}
void solve(){
cin >> n;
for(int i=1;i<=n;++i){
cin >> w[i];
}
for(int len=1;len<=n;++len){
for(int l=1;l+len-1<=n;++l){
int r = l+len-1;
if(len == 1){
f[l][r] = w[l];
g[l][r] = l;
}else{
for(int k=l;k<=r;++k){
int lc = (k==l?1:f[l][k-1]);
int rc = (k==r?1:f[k+1][r]);
int score = lc * rc + w[k];
//维护字典序 只需要维护最左边且最大为root即可
if(score > f[l][r]){
f[l][r] = score;
g[l][r] = k;
}
}
}
}
}
cout << f[1][n] << '\n';
dfs(1,n);
}
int main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}