bzoj P4033 [HAOI2015]树上染色

来源:互联网 发布:java filesystem类 编辑:程序博客网 时间:2024/05/16 11:39

传送门

这道题很妙啊。反正我是想不出来。。

首先有一个很容易想到的状态,设f[i][j]表示子树为i,i涂了j个节点的距离和。嗯这个还是能想到的,然后考虑转移,然后就被虐成zz了。。

分析子树i与儿子所连边的贡献,可以发现这条边的贡献等于他左右两边同色点数乘积和(左黑点数*右黑点数+左白点数*右白点数)。于是我们发现可以进行转移了,就是一个树形dp,f[x][j]=max(f[x][j],f[x][j-l]+f[t[i].v][l]+t[i].w*(l*(k-l)+(size[t[i].v]-l)*(n-size[t[i].v]-k+l)),解释一下,x为当前子树,枚举j(子树的节点数),枚举l(儿子以下的节点数)。

注意:long long炒鸡坑和初始化!!!

代码:

#include<iostream>#include<stdio.h> #include<string.h>#define ll long longusing namespace std;const int Maxn=2010;const ll oo=2e18;struct node{int v;int w;int next;}t[Maxn<<1];ll f[Maxn][Maxn];int head[Maxn],size[Maxn];int n,k,cnt=0;inline void Insert(int u,int v,int w){cnt++;t[cnt].v=v;t[cnt].w=w;t[cnt].next=head[u];head[u]=cnt;}inline void dfs(int x,int fa){size[x]=1;f[x][0]=f[x][1]=0;for(int i=head[x];i;i=t[i].next){if(t[i].v==fa)continue;dfs(t[i].v,x);size[x]+=size[t[i].v];}for(int i=head[x];i;i=t[i].next){        if(t[i].v==fa)continue;        for(int j=min(size[x],k);j>=0;j--)        for(int l=0;l<=min(size[t[i].v],j);l++)        {        ll p=(((ll)t[i].w)*((ll)l)*((ll)(k-l)))+((ll)t[i].w)*((ll)(size[t[i].v]-l))*((ll)(n-size[t[i].v]-k+l));f[x][j]=max(f[x][j],f[x][j-l]+f[t[i].v][l]+p);}}}int main(){int a,b,c;scanf("%d%d",&n,&k);for(int i=1;i<=n-1;i++){scanf("%d%d%d",&a,&b,&c);Insert(a,b,c);Insert(b,a,c);}for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)f[i][j]=-oo;dfs(1,0);printf("%lld",f[1][k]);return 0;}


原创粉丝点击