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;
}

posted @ 2019-04-09 07:27  pkh68  阅读(250)  评论(0编辑  收藏  举报