[HNOI/AHOI2018]道路

${\color{cyan}{>>Question}}$

*不好确定的可以加进状态

方程:

叶节点(边界)

$$f[u][i][j] = c[u]*(a[u]+i)*(b[u]+j)$$

非叶节点:

$$f[u][i][j] = min(f[ls][i+1][j]+f[rs][i][j],f[ls][i][j]+f[rs][i][j+1])$$

但这题更为重要的是空间优化

对于每一层,我们可以给他们的儿子分别附一个编号,同一层编号相同。

因为$u$只由他的儿子转移来,并且他的儿子也只会转移给$u$,所以儿子转移后就没用了,可以让后来的直接覆盖掉儿子

具体实现如下

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std; 

template <typename T> void in(T &x) {
    x = 0; T f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
    while( isdigit(ch)) {x = 10 * x + ch - 48; ch = getchar();}
    x *= f;
}

template <typename T> void out(T x) {
    if(x < 0) x = -x , putchar('-');
    if(x > 9) out(x/10);
    putchar(x%10 + 48);
}
//-------------------------------------------------------

const int N = 20001,k = 19;

int n;
int son[N][2];
int a[N],b[N],c[N];
ll f[80][20][20];

void dfs(int u,int id) {
    int i,j;
    if(u < 0) {
        u = -u;
        for(i = 0;i <= k; ++i) {
            for(j = 0;j <= k; ++j) {
                f[id][i][j] = 1ll*c[u]*(a[u]+i)*(b[u]+j);
            }
        }
        return;
    }
    dfs(son[u][0],id+1); dfs(son[u][1],id+2);
    for(i = 0;i <= k; ++i) {
        for(j = 0;j <= k; ++j) {
            f[id][i][j] = min (
                f[id+1][i+1][j]+f[id+2][i][j],
                f[id+1][i][j]+f[id+2][i][j+1]
            );
        }
    }
}

int main() {
    //freopen("0.in","r",stdin); 
    int i;
    in(n);
    for(i = 1;i < n; ++i) in(son[i][0]),in(son[i][1]);
    for(i = 1;i <= n; ++i) in(a[i]),in(b[i]),in(c[i]);
    dfs(1,1);
    out(f[1][0][0]);
    return 0;
}

 

posted @ 2019-08-14 10:17  陈星卿  阅读(188)  评论(0编辑  收藏  举报