[BZOJ4033] [HAOI2015] 树上染色

题目链接

BZOJ.

洛谷.

Solution

考虑(dp),设(f[x][i])表示(x)的子树选(i)个黑点对答案造成的贡献的最大值。

注意这里是对答案的贡献,对于每条边,如果一侧的黑点个数是(x),白点是(y),那么贡献就是(wcdot (xcdot (k-x)+ycdot (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('
');}

#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;
}
原文地址:https://www.cnblogs.com/hbyer/p/10632155.html