《P1040 [NOIP2003 提高组] 加分二叉树》

$一开始一直在想怎么构造出来的能更优,太傻了。$

$首先数据很小。然后就是有一个很显然的结论。$

$因为是中序遍历,如果以i为根,那么比i小的肯定被分割到它的左子树,比i大的肯定被分割到右子树$

$有了这点我们可以dp去找最优的根,因为这里显然让左右子树的分都尽量大是最优的,所以满足dp性,中间加个记忆化稍微优化一下就行。 $

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef long double ld;
typedef pair<int,int> pii;
const int N = 1e6 + 5;
const int M = 1e4 + 5;
const LL Mod = 998244353;
#define rep(at,am,as) for(int at = am;at <= as;++at)
#define ref(at,am,as) for(int at = am;at >= as;--at)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
inline long long ADD(long long x,long long y) {
    if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
    return (x + y) % Mod;
}
inline long long MUL(long long x,long long y) {
    if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
    return x * y % Mod;
}
inline long long DEC(long long x,long long y) {
    if(x - y < 0) return (x - y + Mod) % Mod;
    return (x - y) % Mod;
}

int n,rt[35][35];
LL dp[35][35],val[35];
LL dfs(int L,int r) {
    if(L > r) return 1;
    if(L == r) {
        rt[L][r] = L;
        return dp[L][r] = val[L];
    }
    if(dp[L][r] != -1) return dp[L][r];
    rep(i,L,r) {
        LL ltmp = dfs(L,i - 1);
        LL rtmp = dfs(i + 1,r);
        if(ltmp * rtmp + val[i] > dp[L][r]) {
            dp[L][r] = ltmp * rtmp + val[i];
            rt[L][r] = i;
        }
    }
    return dp[L][r];
}
void dfs1(int L,int r) {
    if(L > r) return ;
    printf("%d ",rt[L][r]);
    dfs1(L,rt[L][r] - 1);
    dfs1(rt[L][r] + 1,r);
}
void solve() {
    memset(dp,-1,sizeof(dp));
    scanf("%d",&n);
    rep(i,1,n) scanf("%d",&val[i]);
    dfs(1,n);
    printf("%lld\n",dp[1][n]);
    dfs1(1,n);
}   
int main() {
    //int _;
    //for(scanf("%d",&_);_;_--) {
        solve();
    //}
    system("pause");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/15620769.html