bzoj4033 [HAOI2015]树上染色(树形dp)

这题确实有些意思。
考虑f[i][j]表示i子树内选了j个黑点的…什么呢?
这个状态好像不太好设计,因为只管子树内的话子树外的就没机会考虑进答案了qaq
我们考虑一条边w对答案的贡献,一定是w* (左边的白点* 右边的白点+左边的黑点 * 右边的黑点),因此我们可以设计状态为 f[i][j]表示i子树内选了j个黑点,i子树内所有边对答案的贡献的最小值。
然后就可以精细的dp了,复杂度是 O(n2) O ( n 2 ) 的。

”复杂度的证明?考虑那个二重循环,可以看做分别枚举两棵子树的每个点。你会发现,点对(u,v),只会在Tree_Dp(lca(u,v))处被考虑到,所以复杂度是 O(n2) O ( n 2 )
换句话说,i所考虑到的点的DFS序一定小于j所考虑到的点“
以上复杂度的证明摘自ydc博客:portal

#include 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 2010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,h[N],num=0,sz[N];ll f[N][N],g[N];
struct edge{
    int to,next,val;
}data[N<<1];
void dfs(int x,int Fa){
    sz[x]=1;f[x][0]=f[x][1]=0;
    for(int ii=h[x];ii;ii=data[ii].next){
        int y=data[ii].to;if(y==Fa) continue;dfs(y,x);
        memcpy(g,f[x],sizeof(g[0])*(sz[x]+1));memset(f[x],-inf,sizeof(g[0])*(sz[x]+1));
        for(int i=0;i<=sz[x];++i)
            for(int j=0;j<=sz[y];++j){
                if(i+j>m) break;
                f[x][i+j]=max(f[x][i+j],g[i]+f[y][j]+(ll)data[ii].val*(j*(m-j)+(sz[y]-j)*(n-m-sz[y]+j)));
            }
        sz[x]+=sz[y];
    }
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();
    for(int i=1;iint x=read(),y=read(),val=read();
        data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val;
        data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=val;
    }memset(f,-inf,sizeof(f));dfs(1,0);
    printf("%lld\n",f[1][m]);
    return 0;
}

你可能感兴趣的:(bzoj,树形dp)