题解:P12452 [INOI Team Selection 2021] Color Colony
Solution
这题咋和这场比赛的 T1 联动了。。。
如果你很会做最优结构调整,很容易得出这个结论:所有同色边形成一个连通块。
证明是显然的。如果某个颜色构成的边形成至少两个相离的连通块,那么可以将最远的一个和周围“融合”起来。
每次进行一次操作,会使“所有颜色的连通块总数”减少。经过有限步调整之后,一定会满足同色边形成一个连通块。
放一张图让大家理解一下:
比如这有两个橘色边形成的连通块。如果希望跨块产生贡献,一定会包含这条蓝色的边。那么把右边整个连通块变成蓝色的,显然不会变劣。
那么就很好树形 DP 了。设
合并的时候(
但是你显然不能动态更新
然后你要将
次长路径这件事情不需要在 DP 状态中体现,只是转移中有用。使用前缀和优化容易做到
具体来说,我们记
#include<bits/stdc++.h>
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=1e5+10;
int n,k,dp[MAXN][35];
vector<int> G[MAXN];
void dfs(int u,int f) {
int tmp[35][35][2];
memset(tmp,0,sizeof(tmp));
int s=0;
for(auto v:G[u]) if(v!=f) {
dfs(v,u),++s;
int ntmp[35][35][2];
memset(ntmp,0,sizeof(ntmp));
ffor(i,1,k-1) ffor(j,0,min(i,k-1-i)) ffor(o,0,1) {
ntmp[i][j][o|1]=max(ntmp[i][j][o|1],tmp[i][j][o]+dp[v][i]-1+(!o));
ntmp[i][j][o]=max(ntmp[i][j][o],tmp[i][j][o]+dp[v][j]);
}
ffor(i,0,k-1) ffor(j,0,k-1) ffor(o,0,1) tmp[i][j][o]=ntmp[i][j][o];
}
if(!s) dp[u][1]=1;
else {
if(u!=1) ffor(i,1,k-1) ffor(j,0,min(i,k-i-1)) dp[u][j+1]=max(dp[u][j+1],tmp[i][j][1]),dp[u][i+1]=max(dp[u][i+1],tmp[i][j][1]+1);
else {
int ans=0;
ffor(i,1,k-1) ffor(j,0,min(i,k-i-1)) ans=max(ans,tmp[i][j][1]);
cout<<ans;
}
}
ffor(j,1,k-1) dp[u][j]=max(dp[u][j],dp[u][j-1]);
return ;
}
int main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>k;
if(n==1) return cout<<0,0;
ffor(i,1,n-1) {int u,v;cin>>u>>v;G[u].push_back(v),G[v].push_back(u);}
dfs(1,0);
return 0;
}