[BZOJ2159]Crash的文明世界(斯特林数+树形DP)
题意:给定一棵树,求$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得到答案。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 5 using namespace std; 6 7 const int N=50010,K=160,mod=10007; 8 int n,m,l,u,v,now,cnt,A,B,Q,tmp,p[N],f[N][K],S[K][K],fac[K],ans[N]; 9 int to[N<<1],nxt[N<<1],h[N]; 10 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 11 12 void dfs(int x,int fa){ 13 f[x][0]=1; 14 For(i,x) if ((k=to[i])!=fa){ 15 dfs(k,x); f[x][0]=(f[x][0]+f[k][0])%mod; 16 rep(j,1,m) f[x][j]=(f[x][j]+f[k][j]+f[k][j-1])%mod; 17 } 18 } 19 20 void getans(int x,int fa){ 21 rep(i,0,m) ans[x]=(ans[x]+f[x][i]*fac[i]%mod*S[m][i])%mod; 22 For(i,x) if ((k=to[i])!=fa){ 23 for (int j=m; j>=2; j--) 24 f[k][j]=((f[x][j]-f[k][j-1]+f[x][j-1]-f[k][j-1]-f[k][j-2])%mod+mod)%mod; 25 f[k][1]=((f[x][1]-f[k][0]+f[x][0]-f[k][0])%mod+mod)%mod; f[k][0]=n; 26 getans(k,x); 27 } 28 } 29 30 int main(){ 31 scanf("%d%d",&n,&m); 32 rep(i,1,n-1) scanf("%d%d",&u,&v),add(u,v),add(v,u); 33 dfs(1,1); 34 fac[0]=1; rep(i,1,m) fac[i]=fac[i-1]*i%mod; 35 S[0][0]=1; 36 rep(i,1,m) rep(j,1,i) S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%mod; 37 getans(1,1); 38 rep(i,1,n) printf("%d\n",ans[i]); 39 return 0; 40 }