Bzoj5290: [Hnoi2018]道路

BZOJ5290: [Hnoi2018]道路

题目看这里

题解

为什么是pj树型dp。。。
感觉考场上紧张的话写不出很正常啊。。

设置一个状态
\(f[i][x][y]\)表示,第i个节点,往上还有x条路和y条路没有修。
f[i][x][y]=min(f[左儿子][x+1][y]+f[右儿子][x][y],f[左儿子][x][y]+f[右儿子][x][y+1]);
含义是分别是修右儿子,修左儿子。
然后写完了。。。注意的是,卡空间。

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=4e4+5;
int n,a[N],b[N],c[N];
ll f[N][41][41];
int ch[N][2];
ll read(){
    ll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void dfs(ll x,ll left,ll right){
    if(x>=n){
        for(ll i=0;i<=left;i++)
            for(ll j=0;j<=right;j++)
        f[x][i][j]=1ll*c[x]*(a[x]+i)*(b[x]+j);
        return ;
    }
    dfs(ch[x][0],left+1,right+1);dfs(ch[x][1],left+1,right+1);
    for(ll i=0;i<=left;i++){
        for(ll j=0;j<=right;j++){
            ll v1=f[ch[x][0]][i+1][j]+f[ch[x][1]][i][j];
            ll v2=f[ch[x][0]][i][j]+f[ch[x][1]][i][j+1];
            f[x][i][j]=min(v1,v2);
        }
    }
}

int main(){
    n=read();
    for(ll i=1;i<n;i++){
        ll x=read(),y=read();
        if(x<0)x=-x+n-1;if(y<0)y=-y+n-1;
        ch[i][0]=x;ch[i][1]=y;
    }
    for(ll i=n;i<=2*n-1;i++){
        a[i]=read();b[i]=read();c[i]=read();
    }
    dfs(1,0,0);
    cout<<f[1][0][0]<<endl;
    return 0;
}
posted @ 2019-02-16 17:03  Epiphyllum_thief  阅读(91)  评论(0编辑  收藏  举报