[BZOJ2159]Crash的文明世界(斯特林数+树形DP)

时间:2023-03-08 15:54:52

题意:给定一棵树,求$S(i)=\sum_{j=1}^{n}dist(i,j)^k$。
题解:根据斯特林数反演得到:$n^m=\sum_{i=0}^{n}C(n,i)\times i!\times S(m,i)$
故$S(i)=\sum_{k=1}^{m}S(m,k)\times k!\times\sum_{j=1}^{n}C(dist(i,j),k)$
用$f[i][k]$表示$C(dist(i,j),k)$,通过$Pascal$公式:$C(n,m)=C(n,m-1)+C(n-1,m-1)$,用树形DP得到答案。

 #include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
using namespace std; const int N=,K=,mod=;
int n,m,l,u,v,now,cnt,A,B,Q,tmp,p[N],f[N][K],S[K][K],fac[K],ans[N];
int to[N<<],nxt[N<<],h[N];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int x,int fa){
f[x][]=;
For(i,x) if ((k=to[i])!=fa){
dfs(k,x); f[x][]=(f[x][]+f[k][])%mod;
rep(j,,m) f[x][j]=(f[x][j]+f[k][j]+f[k][j-])%mod;
}
} void getans(int x,int fa){
rep(i,,m) ans[x]=(ans[x]+f[x][i]*fac[i]%mod*S[m][i])%mod;
For(i,x) if ((k=to[i])!=fa){
for (int j=m; j>=; j--)
f[k][j]=((f[x][j]-f[k][j-]+f[x][j-]-f[k][j-]-f[k][j-])%mod+mod)%mod;
f[k][]=((f[x][]-f[k][]+f[x][]-f[k][])%mod+mod)%mod; f[k][]=n;
getans(k,x);
}
} int main(){
scanf("%d%d",&n,&m);
rep(i,,n-) scanf("%d%d",&u,&v),add(u,v),add(v,u);
dfs(,);
fac[]=; rep(i,,m) fac[i]=fac[i-]*i%mod;
S[][]=;
rep(i,,m) rep(j,,i) S[i][j]=(S[i-][j-]+S[i-][j]*j)%mod;
getans(,);
rep(i,,n) printf("%d\n",ans[i]);
return ;
}