LGP9479 [NOI 2023] 桂花树 学习笔记
LGP9479 [NOI 2023] 桂花树 学习笔记
前言
六六六,这个树是桂。
这题和 \(\texttt{NOI 2025}\) 的序列变换孰难孰易,这是个问题。
题意简述
你有一棵 \(n\) 个结点的桂花树 \(T\),它满足对于任何一对父子结点 \((i,j)\),总有 \(i<j\)。
给定整数 \(k\)。称一棵 \(n+m\) 个结点的树 \(T'\) 是繁荣的,当且仅当下列条件均满足:
- \(\forall 1\le i<j\le n\),在 \(T\) 和 \(T'\) 上,它们的 \(\text{lca}\) 相同。
- \(\forall 1\le i<j\le (n+m)\),在 \(T'\) 上,它们的 \(\text{lca}\) 编号小于等于 \(\max(i,j)+k\)。
点有标号。问:有多少种繁荣的树?答案对 \(10^9+7\) 取模。
\(n\le 3\times 10^4\),\(m\le 3\times 10^3\),\(k\le 10\)。
做法解析
两个限制,前者看起来比较和蔼可亲,后者看起来非常的申必。手玩一下可以发现,新点要么接在原点的下面,要么接在原边的中间或在中间节外生枝。(你也可以理解为,\(T\) 是 \(T'\) 的一棵虚树)
那后面那个 \(\text{lca}(i,j)\le\max(i,j)+k\) 的限制怎么做?此处一个关键的转化是:考虑从小到大一个一个加新点。这样对于每个新加的点 \(p\),限制就变成 \(\text{lca}(i,p)\le p+k\) 了。这看着好做多了。
\(k=0\) 的时候相当于不可节外生枝。总方案数显然为 \(\prod_{i=n}^{n+m-1}(2i-1)\)。其中 \(i\) 即为每次加点的时候的原树大小。
\(k>0\) 的时候区别在于可以“节外生枝”了,具体来说就是会出现形如 \(\text{lca}(i,n+c)=n+d,c<d\) 的情况。这又怎么办呢。
你再从虚树的视角考虑一下问题就会发现,我们的限制等价于:对于 \([1,n+i]\) 的结点,它们的虚树内的结点编号范围为 \([1,n+i+k]\)。
那么现在要?提示:\(k\le 10\)。
答案是状压。没错又是状压 \(\texttt{DP}\)!我们设 \(f(i,S)\) 为:插入了 \(i\) 个点,并且前 \(k\) 次加入的未被填充的“空白点”的状态用 \(S\) 表示。则转移为:
- 将 \(i+1\) 插在边中间或者挂在点下面,系数为 \(2siz-1\)。
- 将 \(i+1\) 从一条边上衍生出来(相当于选择一条边,往中间插一个空白点占位,再在空白点下面接上 \(i+1\) 号点),系数为 \(siz-1\)。
- 用 \(i+1\) 填上一个空白点。
嗯所以答案和树形态没有关系。哈哈。绷。
代码实现
显然滚动数组了。
\(s\) 的二进制(从 \(1\) 数起)第 \(j\) 位表示对于 \(i\) 来说,这个空白点是由 \(i-j\) 号点拉出来的。
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
using namespace omodint;
using mint=m107;
const int MaxT=1<<10,MaxN=3e4+5;
int N,M,K,tfa[MaxN],alf,ppc[MaxT];
void ovainit(int n){for(int i=0;i<=n;i++)ppc[i]=ppc[i>>1]+(i&1);}
mint ans,F[MaxT],G[MaxT];
void mian(){
readis(N,M,K);ans=0,alf=(1<<K)-1;
for(int i=2;i<=N;i++)readi(tfa[i]);
if(K==0){
ans=1;for(int i=N;i<N+M;i++)ans*=(i*2-1);
writil(miti(ans));return;
}
fill(F,F+alf+1,0),F[0]=1;
for(int i=N;i<N+M;i++){
for(int s=1<<(K-1);s<=alf;s++)G[(s<<1)&alf]+=F[s];
for(int s=0;s<=(1<<(K-1))-1;s++){
for(int j=K-2;j>=0;j--)if((s>>j)&1)G[(s^(1<<j))<<1]+=F[s];
G[s<<1]+=F[s]*((i+ppc[s])*2-1);
G[(s<<1)|1]+=F[s]*(i+ppc[s]-1);
}
for(int s=0;s<=alf;s++)F[s]=G[s],G[s]=0;
}
ans=F[0];writil(miti(ans));
}
int Tpn,Tcn;
int main(){
ovainit(MaxT-1);
readis(Tpn,Tcn);
while(Tcn--)mian();
return 0;
}
浙公网安备 33010602011771号