P3177 [HAOI2015] 树上染色 - 洛谷
思路
首先要想到距离和怎么算:考虑每条边贡献,即经过该边路径数乘权值。
然后就可以设计状态了,\(f_{u,k}\) 代表 \(u\) 为根子 树内有 \(k\) 个黑色的最大答案。
我们考虑转移,想不出来,于是严肃研读题解,发现十分巧妙:依次枚举 \(u\) 的子树的根 \(v\),用当前子树和之前的子树们进行答案的合并,类似淀粉质/启发式合并,可以保证最后的答案是不重不漏的。
Code
#include<bits/stdc++.h>
using namespace std;
const int N=2222;
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
int n,k;
vector<pii>g[N];
int f[N][N]/*当前u子树m个黑,对答案贡献*/,sz[N];
void dfs(int u,int fa){
sz[u]=1;
for(auto x:g[u]){
int v=x.fi,w=x.se;
if(v==fa)continue;
dfs(v,u);
sz[u]+=sz[v];
for(int i=min(k,sz[u]);i>=0;--i){//枚举u子树黑点数
for(int j=max({0ll,i-sz[u]+sz[v],sz[v]+k-n});j<=min(i,sz[v]);++j){//枚举v为rt子树黑点个数
int tot=j*(k-j)+(sz[v]-j)*(n-k-sz[v]+j);//多少对距离经过这边
f[u][i]=max(f[u][i],f[u][i-j]+f[v][j]+tot*w);
}
}
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>k;
for(int i=1;i<n;++i){
int u,v,w;
cin>>u>>v>>w;
g[u].push_back({v,w});
g[v].push_back({u,w});
}
dfs(1,0);
cout<<f[1][k];
return 0;
}
/*
1 0
*/

浙公网安备 33010602011771号