[BZOJ4033] [HAOI2015] 树上染色
题目链接
BZOJ.
洛谷.
Solution
考虑\(dp\),设\(f[x][i]\)表示\(x\)的子树选\(i\)个黑点对答案造成的贡献的最大值。
注意这里是对答案的贡献,对于每条边,如果一侧的黑点个数是\(x\),白点是\(y\),那么贡献就是\(w\cdot (x\cdot (k-x)+y\cdot (n-k-y)))\)。
那么转移就很显然了,直接背包一下就好了。
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
#define ll long long
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
const int maxn = 2e3+10;
const int inf = 1e9;
const lf eps = 1e-8;
ll f[maxn][maxn];
int n,k,head[maxn],tot,sz[maxn];
struct edge{int to,nxt,w;}e[maxn<<1];
void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
void dfs(int x,int fa) {
f[x][0]=f[x][1]=0,sz[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa) dfs(e[i].to,x),sz[x]+=sz[e[i].to];
for(int v,i=head[x];i;i=e[i].nxt) {
if((v=e[i].to)==fa) continue;
for(int s=min(sz[x],k);~s;s--)
for(int j=0;j<=min(s,sz[v]);j++)
if(~f[x][s-j]) f[x][s]=max(f[x][s],f[x][s-j]+f[v][j]+1ll*e[i].w*(j*(k-j)+(sz[v]-j)*(n-k-sz[v]+j)));
}
}
int main() {
read(n),read(k);
for(int i=1,x,y,z;i<n;i++) read(x),read(y),read(z),ins(x,y,z);
memset(f,-1,sizeof f);dfs(1,0);
write(f[1][k]);
return 0;
}