思路
n的范围很小。所以考虑记忆化搜索
dp[l][r]表示这棵树中序遍历中,第l个节点到第r个节点为一棵子树的得分最大值。
那么只需要枚举l到r中每一个点作为根节点即可。
容易得到方程如下
dp[l][r]=max(dp[l][r],dp[l][i-1]*dp[i+1][r]+a[i])
其中l≤i≤r
因为最后输出不仅仅是要最大得分,还需要输出这棵树的前序遍历。
我们现在已经知道中序遍历为1,2,3,4,5.....n要想知道前序遍历只需要知道每个区间的根节点是什么。然后根据根节点去左右dfs即可。
所以再开一个根节点数组root[l][r]表示区间l到r选择的根节点是什么。
在记忆化搜索的时候,注意dfs的边界问题,比如可能出现l>i-1、i+l>r这样,这意味着该树为空树,赋值为1然后return即可。
还有l=r的时候,其实就是遍历到了叶子节点,得分自然就是a[l]
注意开ll

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans;
ll a[35];
ll dp[35][35];
int root[35][35];
void dfs1(int l,int r){
    if(l==r){
        dp[l][r]=a[l];
        root[l][r]=l;
        return ;
    }
    if(l>r) {
        dp[l][r]=1;
        return ;
    }
    if(dp[l][r]==0){
        for(int i=l;i<=r;i++){
             dfs1(l,i-1);
             dfs1(i+1,r);
             ll q=dp[l][i-1]*dp[i+1][r]+a[i];
             if(q>dp[l][r]){
                dp[l][r]=q;
                root[l][r]=i;
             }
             ans=max(ans,dp[l][r]);
        }
    }
}
void dfs2(int l,int r){
    if(l>r) return ;
    cout<<root[l][r]<<" ";
    dfs2(l,root[l][r]-1);
    dfs2(root[l][r]+1,r);
}
int main(){

    int n;cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    dfs1(1,n);
    cout<<ans<<endl;
    dfs2(1,n);
    return 0;
}