舒阳 的博客

舒阳 的博客

QAQ QWQ

题解 P1040 【加分二叉树】

posted on 2019-10-28 23:44:34 | under 题解 |

思路

区间DP(类似于)

一开始我设计的状态是f[L][R][rot]表示在中序遍历的区间[L, R]中选取rot为根节点,得到的最大加分。

后来翻看题解发现,状态中的rot项并不重要,对于第一问,我们只关心$[L, R]$区间中构建成一棵树后得到的最大加分值,不关心这棵树的形态。

于是设计状态为f[L][R]在区间[L, R]为中序遍历时,形成的最大加分值。

转移过程中枚举区间$[L, R]$中的一个点作为根节点,计算加分,更新$f[i][j]$。

对于输出先序遍历,我们需要知道每一段$[L, R]$中的根结点时那个才能构造出先序遍历,简单说就是需要知道树的形态。可以在转移的过程中进行记录,例如$root[L][R]$表示在中序遍历的区间中$[L, R]$的根节点。

/*!
 * FileName: luogu-1040.cpp
 * This Problem is on luogu. The ID of the problem is 1040. 
 * Copyright(c) 2019 Shu_Yu_Mo
 * MIT Licensed
 * Luogu: https://www.luogu.org/space/show?uid=44615
 * Github: https://github.com/oldsuold/
 * Gitee: https://gitee.com/Shu_Yu_Mo/
 * These words were created by an amazing tool on 2019-10-27 08:43:19 written by Shu_Yu_Mo.
 */
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstring>
#include<iostream>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
#define _R register 
#define inf 0x7fffffff
using namespace std;
const int _ = 110;
inline int read()
{
    char c = getchar(); int sign = 1; int x = 0;
    while(c > '9' || c < '0') { if(c=='-')sign = -1; c = getchar(); } 
    while(c <= '9' && c >= '0') { x *= 10; x += c - '0'; c = getchar(); }
    return x * sign;
}
int n;
int A[_]; 
int f[_][_];
int root[_][_];
void printTree(int L, int R){
    if(L == R){
        printf("%d ", L);
        return ;
    }
    if(L > R) return ;
    int rt = root[L][R];
    printf("%d ", rt);
    printTree(L, rt - 1);
    printTree(rt + 1, R);
}
int main()
{
    n = read();
    for(_R int i = 1;i <= n;i++) A[i] = read();
    for(_R int i = 0;i <= n;i++){
        for(_R int j = 0;j < i;j++)
            f[i][j] = 1;
    }
    for(_R int i = 1;i <= n;i++)f[i][i] = A[i], root[i][i] = i;
    for(_R int len = 2;len <= n;len++){
        for(_R int L = 1;L + len - 1 <= n;L++){
            int R = L + len - 1;
            for(_R int k = L;k <= R;k++){
                if(f[L][R] < f[L][k - 1] * f[k + 1][R] + A[k]){
                    f[L][R] = f[L][k - 1] * f[k + 1][R] + A[k];
                    root[L][R] = k; 
                }
            }
        }
    }
    printf("%d\n", f[1][n]);
    printTree(1, n);
    return 0;
}