*不好确定的可以加进状态
方程:
叶节点(边界)
$$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; }