题没想出来很烦+一堆细节要注意很烦。
当然更可能是我智商被osu吃了。
考虑一条边会有什么贡献?它一边的黑点数*另一边的黑点数*边权。
+它一边的白点数*另一边的白点数*边权。
这样一来就成了一个树形背包
#include<cstring> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cctype> #define maxn 2030 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch==‘-‘) f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-‘0‘; ch=getchar(); } return num*f; } struct Edge{ long long next,to,dis; }edge[maxn*3]; long long head[maxn],num; inline void add(long long from,long long to,long long dis){ edge[++num]=(Edge){head[from],to,dis}; head[from]=num; } long long n,m; long long size[maxn]; long long f[maxn][maxn]; void build(long long x,long long fa){ size[x]=1; for(long long i=head[x];i;i=edge[i].next){ long long to=edge[i].to; if(to==fa) continue; build(to,x); size[x]+=size[to]; } } inline long long calc(long long i,long long x){ return (m-x)*x*edge[i].dis+(n-m+x-size[edge[i].to])*(size[edge[i].to]-x)*edge[i].dis; } void dfs(long long x,long long fa){ memset(f[x],-1,sizeof(f[x])); f[x][0]=f[x][1]=0; for(long long i=head[x];i;i=edge[i].next){ long long to=edge[i].to; if(to==fa) continue; dfs(to,x); for(long long j=min(m,size[x]);j>=0;--j){ for(long long k=0;k<=min(j,size[to]);++k) if(f[x][j-k]!=-1) f[x][j]=max(f[x][j],f[x][j-k]+f[to][k]+calc(i,k)); } } return; } int main(){ n=read(),m=read(); for(long long i=1;i<n;++i){ long long from=read(),to=read(),dis=read(); add(from,to,dis); add(to,from,dis); } build(1,1); dfs(1,1); printf("%lld\n",f[1][m]); return 0; }