题解:CF1097G Vladislav and a Great Legend

帝安诺

2024-11-16 09:11:44

Solution

思路

先令 f(\varnothing)=0,那么原式转为 \sum_{X \sube U} (f(X))^k,容易发现这对答案不会造成影响。
由普通幂转下降幂:

x^k=\sum_{i=0} \begin{Bmatrix} k\\i \end{Bmatrix} \dbinom{x}{i} i!

其中 \begin{Bmatrix} k\\i \end{Bmatrix} 是第二类斯特林数。

带入到原式:

\begin{aligned} \sum_{X \sube U} (f(X))^k &= \sum_{X \sube U}\sum_{i=0} \begin{Bmatrix} k\\i \end{Bmatrix} \dbinom{f(X)}{i} i!\\ &=\sum_{i=0}\begin{Bmatrix} k\\i \end{Bmatrix}i!\sum_{X \sube U} \dbinom{f(X)}{i} \end{aligned}

注意到 \begin{Bmatrix} k\\i \end{Bmatrix}i! 可以预处理,于是我们只用尝试求解 \sum_{X \sube U} \dbinom{f(X)}{i}

考虑组合意义,容易发现 \dbinom{f(X)}{i} 的一个意义是从虚树中选 i 条边出来染色的方案数,我们由此入手。

考虑 dp,容易设计出状态 f_{x,i} 表示以 x 为根的子树中的虚树的染色方案数(x 这个点可以不选,但虚树必须经过 x)。
但是这样难以转移,于是再设计辅助状态 g_{x,i} 表示以 x 为根的子树及 father(x)-x 这条边(后称作父边)必须作为虚树边的染色方案数(x 这个点同样可以不选,父边必须当作虚树边但可以不染色)。
(你会发现 g_{x,i} 在根结点处的定义不清楚,但是根结点处的 g_{x,i} 作为辅助状态不会再往上转移了,所以我们不妨忽略这个问题,或者你也可以认为根结点有一根虚拟父边。)

考虑转移,容易发现:

f_{x,i+j}=f_{x,i} \times g_{y,j},y \in son(x) $$ g_{x,0}=f_{x,0}\\ g_{x,i}=f_{x,i}+f_{x,i-1} $$ 另外此时 $g_{x,1}$ 会计入一颗空树(仅有父边且染色),需要减一。 注意到此时的 $f_{x,i}$ 还有不合法的情况未剔除,具体来说是所有虚树点都在一颗子树中且 $x$ 本身不选的情况,于是有: $$ f_{x,i}=f_{x,i}-\sum_{y \in son(x)} g_{y,i} $$ 注意上面这一步要在求完 $g_{x,i}$ 后再进行(因为对于 $g_{x,i}$ 而言,上面那种情况是合法的)。 最后是统计答案,显然直接把每个点的 $f_{x,i}$ 计入 $\sum_{X \sube U} \dbinom{f(X)}{i}$ 即可。 时间复杂度 $O(nk)$。 ## code: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5+10,M=210,mod=1e9+7; int n,K,sum; int S[M][M],f[N][M],g[N][M],tmp[M],siz[N],fac[N],ans[N]; vector<int> tr[N]; void add(int x,int y){ tr[x].push_back(y); return; } void init(){ S[1][1]=1,fac[0]=1; for(int i=2;i<=200;i++) for(int j=1;j<=i;j++) S[i][j]=(S[i-1][j-1]+S[i-1][j]*j%mod)%mod; for(int i=1;i<=200;i++) fac[i]=fac[i-1]*i%mod; return; } void dfs(int x,int fa){ siz[x]=1,f[x][0]=2; for(int y : tr[x]){ if(y==fa) continue; dfs(y,x); for(int i=0;i<=K;i++) tmp[i]=0; for(int i=0;i<=min(siz[x],K);i++){ for(int j=0;j<=min(siz[y],K-i);j++){ tmp[i+j]=(tmp[i+j]+f[x][i]*g[y][j]%mod)%mod; } } siz[x]+=siz[y]; for(int i=0;i<=K;i++) f[x][i]=tmp[i]; } g[x][0]=f[x][0]; for(int i=1;i<=K;i++) g[x][i]=(f[x][i]+f[x][i-1])%mod; g[x][1]=(g[x][1]-1+mod)%mod; for(int y : tr[x]) if(y!=fa) for(int i=0;i<=K;i++) f[x][i]=(f[x][i]-g[y][i]+mod)%mod; for(int i=0;i<=K;i++) ans[i]=(ans[i]+f[x][i])%mod; return; } signed main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); init(); cin>>n>>K; for(int i=1,x,y;i<n;i++){ cin>>x>>y; add(x,y),add(y,x); } dfs(1,0); for(int i=0;i<=K;i++){ sum=(sum+fac[i]*S[K][i]%mod*ans[i]%mod)%mod; } cout<<sum; return 0; } ```