1. 程式人生 > 其它 >CF1481F AB Tree 題解

CF1481F AB Tree 題解

Codeforces
Luogu

Description.

給定 \(n\) 個點的樹,\(1\) 是根,染出 \(k\) 個白點 \(n-k\) 個黑點。
求出最少的本質不同的從根走到某個節點連成的字串數,並構造。

Solution.

首先考慮沒有 \(k\) 的限制,肯定每層染相同。
那麼最小值肯定是 \(\max\{\text{dep}_i\}\)
考慮最大值,發現最大可能是 \(\max\{\text{dep}_i\}+1\),證明參考下文構造。

所以直接揹包判斷最大值是不是 \(\max\{\text{dep}_i\}\),是就直接揹包輸出方案,否則就用另一種方法構造。
但是樸素揹包是 \(O(\frac{n^2}\omega)\)

的,空間都開不下。
但是本質不同的數量是 \(O(\sqrt n)\) 的,優化成了 \(O(\sqrt n\log n\frac{n}{\omega})\)
看上去很能過,就寫了。

然後構造的話就直接按層構造,然後把葉子非葉子分開。
然後最左邊、最上面全都染成黑色,否則染成白色。
考慮證明,分界點如果在葉子節點中,證明顯然,否則證明顯然。
然後就做完了。

Coding.

點選檢視程式碼
//是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=100005;int n,K,rr[N],idt,rrt,vs[N],rs[N],dg[N];
bitset<N>dp[5266];vector<int>v[N],cn[N],id[N],e[N],vi;
inline void pull(int nw,int vl)
{
	if(nw==0) return;else if(dp[nw-1][vl]) pull(nw-1,vl);
	else rr[++rrt]=nw,pull(nw-1,vl-vi[nw-1]);
}
inline void dfs(int x,int d) {v[d].push_back(x);for(auto y:e[x]) dfs(y,d+1),dg[x]++,dg[y]++;}
int main()
{
	read(n,K),dp[0][0]=1;int mxd=0;for(int i=2,x;i<=n;i++) read(x),e[x].push_back(i);//dep 出現次數
	dfs(1,1);for(int i=1;i<=n;i++) if(!v[i].empty()) cn[v[i].size()].push_back(i),mxd=i;//出現次數次數
	for(int i=1;i<=n;i++) if(!cn[i].empty())//相當於多重揹包的元素
	{
		int cnt=cn[i].size(),gg=0,nw=1;
		for(;gg<cnt;gg+=nw,nw<<=1)
		{
			++idt,vi.push_back(i*min(nw,cnt-gg));//第 idt 個揹包裡的所有 dep
			for(int j=gg;j<cnt&&j<gg+nw;j++) id[idt].push_back(cn[i][j]);
		}
	}
	for(int i=1;i<=idt;i++) dp[i]=dp[i-1]|(dp[i-1]<<vi[i-1]);
	int wh=0;for(int i=K;i>=0;i--) if(dp[idt][i]) {wh=i;break;}
	pull(idt,wh);for(int i=1;i<=rrt;i++) for(auto x:id[rr[i]]) vs[x]=1;
	if(wh==K)
	{
		printf("%d\n",mxd);
		for(int i=1;i<=n;i++) if(vs[i]) for(auto w:v[i]) rs[w]=1;
		for(int i=1;i<=n;i++) putchar('b'-rs[i]);
		return putchar('\n'),0;
	}else printf("%d\n",mxd+1);
	int fg=1,x=K,y=n-K;for(int i=1;i<=n;i++)
	{
		sort(v[i].begin(),v[i].end(),[](int a,int b){return dg[a]>dg[b];});
		x<y?swap(x,y),fg^=1:0;for(size_t j=0;j<v[i].size();j++)
			rs[v[i][j]]=fg,x--,(!x?swap(x,y),fg^=1:0);
	}
	for(int i=1;i<=n;i++) putchar('b'-rs[i]);
	return putchar('\n'),0;
}