CF1338D Nested Rubber Bands 题解
首先画几个图玩一下,然后可以发现对答案的贡献是如下这种形式:
然后再进一步,他还可以是这种形式:
然后你试图把他扩展到一般形式,发现他限制非常多。
例如下图:
这是他的最优解,注意三个三叉子树只有一个能被完全选入。
原理大概是这样的:
所以一个点只有最多一个子树能被完全计入答案,其他的儿子只有一层有效。
仔细分析一下,发现他答案是找一条链,只保留一级儿子的最大独立集的大小,这个可以通过简单的树形 DP 求出。
题解部分讲完了,下面是一些题外话。
这道题我在 cf 的现场已经想到了全部的解法,但是因为一些失误,导致我在一个统计答案的地方少了一个 \(+1\) ,然后他的 pretest 虽然有 \(27\) 个数据点,但没有一个数据点包含了这个细节,于是我 fst 了。而由于前面 A、C 两题的一些高级操作(一场比赛中连着 \(2\) 题没开 long long ,分别贡献了一发罚时),而且由于切题顺序的问题 (\(A\rightarrow C\rightarrow B\)),导致我罚时巨大,最后排在了 rk200+ 的位置。
还好我本来的 rating 很低,所以还是上了一点分,还变成了 IM。
这应该是一道好题,他思维难度大,代码难度小(适合我这种不会写代码的人,虽然我还是 fst 了)
Code:
#define N 100005
vector<int> G[N];
bool cmp(int x,int y){return x>y;}
int f[N][2],dep[N],maxd[N],n,ans; // not choose , choose
void dfs(int u,int fa)
{
int maxn=0,cnt=0;
vector<int> a,b,c;
for(int v:G[u])
{
if(v==fa) continue;
dfs(v,u); cnt++;
a.pb(f[v][0]);
b.pb(f[v][1]);
c.pb(max(f[v][0],f[v][1]));
}
sort(a.begin(),a.end(),cmp);
sort(b.begin(),b.end(),cmp);
sort(c.begin(),c.end(),cmp);
if(a.size()==0)
{
f[u][1]=1; return ;
}
if(a.size()==1)
{
f[u][1]=1+a[0];
f[u][0]=max(a[0],b[0]);
return ;
}
if(u==1)
{
int R=cnt-2+c[0]+c[1];
if(R>ans) ans=R;
R=a[0]+a[1]+1; // 我少了一个 +1 的地方
if(R>ans) ans=R;
f[u][0]=cnt-1+c[0];
f[u][1]=1+a[0];
}
else
{
int R=cnt-1+c[0]+c[1];
if(R>ans) ans=R;
R=a[0]+a[1]+1; // 还有这里
if(R>ans) ans=R;
f[u][0]=cnt-1+c[0];
f[u][1]=1+a[0];
}
}
signed main()
{
cin>>n;
for(int i=1;i<n;i++)
{
int u=read(),v=read();
G[u].pb(v),G[v].pb(u);
}
dfs(1,0);
cout<<max(ans,max(f[1][0],f[1][1]))<<endl;
return 0;
}