CF1097G Vladislav and a Great Legend
CF1097G Vladislav and a Great Legend
题面:Luogu
解析
\[\sum_{X \subseteq \{1,2...n\}} f(X)^k
\]
\[=\sum_{X} \sum_{i=0}^{k} S(k,i) \times i! \times {f(X) \choose i}
\]
\[=\sum_{i=0}^{k} S(k,i) \times i! \times \sum_{X} {f(X) \choose i}
\]
考虑计算后面的式子,从组合意义去考虑,那么后面的式子等价于枚举大小为\(i\)的边集\(S\),计算有多少选出的点集\(X\)的生成树中包含的方案数之和。
不妨以点集\(X\)中深度最小的点\(x\)来计算贡献,设\(f(x,i)\)表示在以\(x\)为根的子树中选出大小为\(i\)的边集\(S\),而生成树包含\(S\)的点集的方案数之和,不难发现大小为\(i\)的边集\(S\)的贡献即为\(g(i)=\sum_{x=1}^n f(1,i)\)。
那么如何计算\(f(x,i)\)呢?我们考虑枚举\(i\)条边如何分配给\(x\)的儿子,不难发现生成树就是由若干颗生成树拼合而成,那么直接树上背包统计即可。先考虑初始情况,即\(f(x,0)\)。根据定义,有\(f(x,0)=2\),即不选\(x\)和选\(x\)。对于\(f(x,i)(i \gt 0)\),有\(f'(x,k)=\sum_{k=i+j} f(x,i) \times f(v,j)\)。注意这里的\(f(v,i)=f(v,i)+f(v,i-1)\),因为要枚举是否选择\(x\)到\(v\)的边。然而这样有两种不合法的情况,一种是子树内没有选点(即\(f(v,0)\)中的一种情况),这样是不能统计到\(f(v,1)\)的,所以\(f(v,1)\)要减掉1,另一种是子树\(v\)外没有选点,但是却选择了\(x\)到\(v\)的边,这种情况要减掉多统计的\(f(v,i-1)\)。
代码
#include<cstdio>
#define N 100005
#define K 205
using namespace std;
const int P=1e9+7;
inline int In(){
char c=getchar(); int x=0,ft=1;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x*ft;
}
inline int min(int a,int b){
return a<b?a:b;
}
int n,k_p,h[N],e_tot=0;
struct E{ int to,nex; }e[N<<1];
inline void add(int u,int v){
e[++e_tot]=(E){v,h[u]}; h[u]=e_tot;
}
int S[K][K],fac[K];
inline void Get_S_fac(){
fac[0]=1; for(int i=1;i<=k_p;++i) fac[i]=1ll*i*fac[i-1]%P;
S[0][0]=1;
for(int i=1;i<=k_p;++i)
for(int j=1;j<=i;++j)
S[i][j]=(S[i-1][j-1]+1ll*j*S[i-1][j]%P)%P;
}
int sz[N],f[N][K],ans=0,t1[K],g[K];
void dp(int u,int pre){
f[u][0]=2; sz[u]=1;
for(int c=h[u],v;c;c=e[c].nex){
if((v=e[c].to)==pre) continue; dp(v,u);
for(int i=0;i<=min(k_p,sz[u]+sz[v]-1);++i) t1[i]=0;
for(int i=0;i<sz[u]&&i<=k_p;++i)
for(int j=0;j<=sz[v]&&i+j<=k_p;++j)
t1[i+j]=(t1[i+j]+1ll*f[u][i]*f[v][j]%P)%P;
sz[u]+=sz[v];
for(int i=0;i<sz[u]&&i<=k_p;++i) f[u][i]=t1[i];
}
if(u==1) for(int i=0;i<=k_p;++i) g[i]=(g[i]+f[u][i])%P;
else{
for(int i=1;i<=k_p;++i) g[i]=(g[i]-f[u][i-1]+P)%P;
g[1]=(g[1]+1)%P;
}
for(int i=k_p;i;--i) f[u][i]=(f[u][i]+f[u][i-1])%P;
f[u][1]=(f[u][1]+P-1)%P;
}
int main(){
n=In(); k_p=In();
for(int i=1,u,v;i<n;++i){
u=In(); v=In();
add(u,v); add(v,u);
}
dp(1,-1); Get_S_fac();
for(int i=0;i<=k_p;++i)
ans=(ans+1ll*S[k_p][i]*fac[i]%P*g[i]%P)%P;
printf("%d\n",ans);
return 0;
}