题意

传送门
给一棵树
求每个点\(S(i)=\sum\limits_{j=1}^ndist(i,j)^k\)。对10007取模。

思路

已知:\(n^k=\sum\limits_{i\ge 0}\left\{ \dfrac{k}{i} \right\} n^{\underline{i}}\)
直接推答案柿子:

\(ans_x\)

\(=\sum\limits_{i=1}^n i! \sum\limits_{j=0}^k \left\{ \dfrac{k}{j} \right\} dis(x,i)^{\underline{j}}\)

\(=\sum\limits_{i=1}^n \sum\limits_{j=0}^k \left\{ \dfrac{k}{j} \right\} \dbinom{dis(x,i)}{j} j!\)

\(=\sum\limits_{j=0}^k \left\{ \dfrac{k}{j} \right\} j! \sum\limits_{i=1}^n\dbinom{dist(x,i)}{j}\)

\(=\sum\limits_{j=0}^k \left\{ \dfrac{k}{j} \right\} j! \sum\limits_{i=1}^n(\dbinom{dist(x,i)-1}{j}+\dbinom{dist(x,i)-1}{j-1})\)

因此可以通过组合数递推,反推到树上dp递推(距离减一不就是儿子的状态吗),存状态\(dp[u][j]\)\(u\)子树内,所有点\(i\)\(u\)贡献\(\dbinom{dist(u,i)}{j}\)的贡献和。
递推柿很简洁:\(dp[u][j]=dp[son][j]+dp[son][j-1]\)
含义为:所有点到\(u\)贡献\(\dbinom{dist(u,i)}{j}\)可以划分为所有点到\(son\)贡献\(\dbinom{dist(son,i)}{j}+\dbinom{dist(son,i)}{j-1}\)

因此想要把数学推理到dp上来,就要了解这个抽象的数学柿子表达的什么意思。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5;
const int M=155;
const int mod=10007;
int jc[N],S[M][M],n,K;
int dp[N][M],nxt[N<<1],to[N<<1],head[N],ecnt;
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
void dfs1(int u,int fa) {
	dp[u][0]=1;
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa)continue;
		dfs1(v,u);
		for(int j=1;j<=K;j++) {dp[u][j]=(dp[u][j]+dp[v][j]+dp[v][j-1])%mod;}
		dp[u][0]=(dp[u][0]+dp[v][0])%mod;
	}
}

int ans[N];
void dfs2(int u,int fa) {
	int tmp[M];
	for(int j=0;j<=K;j++) {ans[u]=(ans[u]+S[K][j]*jc[j]%mod*dp[u][j])%mod;tmp[j]=dp[u][j];}
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];if(v==fa)continue;
		for(int j=1;j<=K;j++) {dp[u][j]=(dp[u][j]-dp[v][j]-dp[v][j-1])%mod;}
		dp[u][0]=(dp[u][0]-dp[v][0])%mod;

		for(int j=1;j<=K;j++) {dp[v][j]=(dp[v][j]+dp[u][j]+dp[u][j-1])%mod;}
		dp[v][0]=(dp[v][0]+dp[u][0])%mod;
		dfs2(v,u);
		for(int j=0;j<=K;j++) dp[u][j]=tmp[j];
	}
}

void init() {
	S[0][0]=1;
	for(int i=1;i<=K;i++) {
		S[i][0]=0;
		for(int j=1;j<=i;j++) {
			S[i][j]=(S[i-1][j-1]+j*S[i-1][j])%mod;
		}
	}
	jc[0]=1;for(int i=1;i<=n;i++)jc[i]=jc[i-1]*i%mod;
}

int main() {
	scanf("%d%d",&n,&K);
	init();
	for(int i=1;i<n;i++) {int u,v;scanf("%d%d",&u,&v);add_edge(u,v),add_edge(v,u);}
	dfs1(1,0),dfs2(1,0);
	for(int i=1;i<=n;i++) {printf("%d\n",(ans[i]+mod)%mod);}
	return 0;
}