T2.coloration
树形DP,提供了一种好的思路。
涉及考虑树上点对的题,与其O(n^2)地考虑任意两点的关系,不如考虑每条边的贡献。
本题中,对于一条边e,它的边权为w,其贡献为 (左侧黑点*右侧黑点+左侧白点*右侧白点)*w
设f[i][j]为以i为根的子树中选取j个黑点的最大贡献,转移时逐个合并子树,用一个g数组先跑一次背包,再添加进f状态。
复杂度O(n^2),卡好边界。
注意int到long long要乘一个1ll
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int MAXN=2048; inline int rd() { int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } struct Edge { int next,to,w; } e[MAXN<<1]; int ecnt,head[MAXN]; inline void add(int x,int y,int w) { e[++ecnt].to = y; e[ecnt].next = head[x]; e[ecnt].w = w; head[x] = ecnt; } int n,m; long long f[MAXN][MAXN],g[MAXN]; int siz[MAXN]; int dfs(int x,int pre) { siz[x]=1; for(int i=head[x]; i; i=e[i].next) { int v=e[i].to; if(v==pre) continue; memset(g,0,sizeof(g)); dfs(v,x); for(int j=min(m,siz[x]); j>=0; j--) for(int k=min(m-j,siz[v]); k>=0; k--) g[j+k]=max(g[j+k], f[x][j]+f[v][k]+((k*(m-k)+(siz[v]-k)*(n-m-siz[v]+k))*1ll*e[i].w)); for(int j=0; j<=m; j++)f[x][j]=g[j]; siz[x]+=siz[v]; } } int main() { n=rd(); m=rd(); int x,y,w; for(int i=1; i<=n-1; i++) { x=rd();y=rd();w=rd(); add(x,y,w);add(y,x,w); } dfs(1,0); cout<<f[1][m]; }