CF1481F 题解
DaiRuiChen007 · · 题解
CF1481F 题解
Problem Link
题目大意
给一棵
n 个点的树,给每个点填0/1 ,最终要求填0 的点恰有x 个,最小化所有1\to i 形成的 01 串中本质不同字符串的数量,给出构造。数据范围:
n\le 10^5 。
思路分析
首先考虑最理想情况,当且仅当每层都填同一个数才能取得最小值,此时答案等于最大深度
然后考虑一般的情况,显然只有一层不是全部同色,显然我们想让某种颜色的节点全在叶子上,此时就能取到
从第一层开始,维护两种颜色剩下的数量
c_0,c_1 ,假设当前处理到第i 层,且该层非叶子节点有t 个,且i\sim D 层还剩下m 个节点,我们能得到\max(c_0,c_1)\ge\left\lfloor \dfrac m2\right\rfloor\ge t ,因此用余量更多的一种去填非叶节点即可。对于叶节点,依然用同种颜色去填,如果能填完,则没有新建字符串,处理下一层。
如果不能填完,那么剩下部分用另一种颜色去填,此时
i+1\sim D 层全部同色,只有i 层不是完全同色。此时我们就构造了一组
D+1 的方案。
然后考虑如何判定答案是否可能为
此时空间过大,考虑优化,注意到
时间复杂度
代码呈现
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
bitset <MAXN> dp[505],tmp;
int dep[MAXN],tot,cnt[MAXN];
vector <int> G[MAXN],ver[MAXN],blo[MAXN];
char str[MAXN];
inline void dfs(int u,int fa) {
ver[dep[u]=dep[fa]+1].push_back(u);
tot=max(tot,dep[u]);
for(int v:G[u]) dfs(v,u);
}
signed main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=2,p;i<=n;++i) scanf("%d",&p),G[p].push_back(i);
dfs(1,0);
dp[0].set(0);
vector <int> sz;
for(int i=1;i<=tot;++i) {
int k=ver[i].size();
blo[k].push_back(i);
sz.push_back(k);
}
sort(sz.begin(),sz.end());
sz.erase(unique(sz.begin(),sz.end()),sz.end());
int cnt=sz.size();
sz.insert(sz.begin(),0);
for(int t=1;t<=cnt;++t) {
int i=sz[t]; tmp=dp[t-1];
for(int j=0;j<=(int)blo[i].size();++j) {
dp[t]|=tmp,tmp<<=i;
}
}
if(dp[cnt][m]) {
printf("%d\n",tot);
for(int t=cnt;t>=1;--t) {
int i=sz[t];
for(int j=0;j<=(int)blo[i].size();++j) if(dp[t-1][m-i*j]) {
m-=i*j;
for(int k=0;k<j;++k) {
for(int u:ver[blo[i][k]]) str[u]='a';
}
for(int k=j;k<(int)blo[i].size();++k) {
for(int u:ver[blo[i][k]]) str[u]='b';
}
break;
}
}
} else {
printf("%d\n",tot+1);
int ca=m,cb=n-m;
for(int i=1;i<=tot;++i) {
sort(ver[i].begin(),ver[i].end(),[&](int x,int y){ return G[x].size()>G[y].size(); });
bool o=ca>cb;
for(int j:ver[i]) {
if(o) str[j]='a',o^=!(--ca);
else str[j]='b',o^=!(--cb);
}
}
}
printf("%s\n",str+1);
return 0;
}