CF1097G Vladislav and a Great Legend 解题报告

CF1097G Vladislav and a Great Legend解题报告:

更好的阅读体验

题意

给定一个 (n) 个节点的树,定义 (f(S))(S) 的虚树边数,给定常数 (k),求:

[sum_{Sin{1,2,cdots,n},S evarnothing}f(S)^k ]

分析

考虑用斯特林数拆开 (k) 次幂:

[sum_{Sin{1,2,cdots,n},S evarnothing}sum_{i=0}^negin{Bmatrix}k\iend{Bmatrix}{f(S)choose i}i!\=sum_{i=0}^negin{Bmatrix}k\iend{Bmatrix}i!sum_{Sin{1,2,cdots,n},S evarnothing}{f(S)choose i} ]

考虑计算后面的贡献,可以考虑用树上背包来计算,这是平凡的。

代码

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=100005,maxk=205,mod=1000000007;
int n,k,ans;
int S[maxn][maxk],g[maxk],f[maxn][maxk],sz[maxn],fac[maxn],tot[maxn];
vector<int>v[maxn];
void dfs(int x,int last){
	sz[x]=1,f[x][0]=2;
	for(int i=0;i<v[x].size();i++)
		if(v[x][i]!=last){
			int y=v[x][i];
			dfs(y,x);
			for(int u=0;u<=sz[y]&&u<=k;u++)
				tot[u]=(tot[u]-f[y][u]+mod)%mod;
			for(int u=0;u<=sz[x]&&u<=k;u++)
				for(int v=0;v<=sz[y]&&u+v<=k;v++)
					g[u+v]=(g[u+v]+1ll*f[x][u]*f[y][v])%mod;
			sz[x]+=sz[y];
			for(int u=0;u<=k;u++)
				f[x][u]=g[u],g[u]=0;
		}
	for(int i=0;i<=k;i++)
		tot[i]=(tot[i]+f[x][i])%mod;
	for(int i=k;i>=1;i--)
		f[x][i]=(f[x][i]+f[x][i-1])%mod;
	f[x][1]=(f[x][1]-1+mod)%mod;
}
int main(){
	scanf("%d%d",&n,&k);
	fac[0]=fac[1]=S[1][1]=1;
	for(int i=2;i<=k;i++){
		fac[i]=1ll*fac[i-1]*i%mod;
		for(int j=1;j<=k;j++)
			S[i][j]=(S[i-1][j-1]+1ll*j*S[i-1][j])%mod;
	}
	for(int i=1,x,y;i<n;i++)
		scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
	dfs(1,0);
	for(int i=0;i<=k;i++)
		ans=(ans+1ll*S[k][i]*fac[i]%mod*tot[i])%mod;
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/xiaoziyao/p/15264414.html