CF1481F AB Tree 題解
阿新 • • 發佈:2021-10-20
Link.
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; }