题没想出来很烦+一堆细节要注意很烦。
当然更可能是我智商被osu吃了。
考虑一条边会有什么贡献?它一边的黑点数*另一边的黑点数*边权。
+它一边的白点数*另一边的白点数*边权。
这样一来就成了一个树形背包
#include#include #include #include #include #define maxn 2030using 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