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) imes i! imes {f(X) choose i}
]
[=sum_{i=0}^{k} S(k,i) imes i! imes 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) imes 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
",ans);
return 0;
}