1. 程式人生 > >Crash 的文明世界

Crash 的文明世界

題目描述

給一棵樹,求以每個點為根時下列式子的值。

題解

當k=1時這就是一個經典的換根dp問題。

所以這道題還是要用換根dp解決。

部分分做法:

考慮轉移時是這樣的一個形式(圖是抄的)。

用二項式定理展開就可以nk2做了。

觀察到結果是一個xk的形式。

然後這個可以用斯特林數代換。

我們可以先求出每個點的後面的東西,在乘上前面的就是答案了。

這是個組合數,可以用組合數的遞推解決。

程式碼

#include<iostream>
#include<cstdio>
#define N 50009
#define KK 151
using
namespace std; typedef long long ll; const int mod=10007; int dp[N][KK],f[KK],h[KK],jie[KK]; int n,m,a[N],tot,head[N],K,s[KK][KK]; inline ll rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x; } struct edge{int n,to;}e[N<<1]; inline void add(int u,int v){ e[++tot].n=head[u];e[tot].to=v;head[u]=tot; e[++tot].n=head[v];e[tot].to=u;head[v]=tot; } void dfs(int u,int fa){ dp[u][0]=1; for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){ int v=e[i].to;dfs(v,u); (dp[u][
0]+=dp[v][0])%=mod; for(int j=1;j<=K;++j)(dp[u][j]+=dp[v][j]+dp[v][j-1])%=mod; } } void dfs2(int u,int fa){ for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){ int v=e[i].to; for(int j=0;j<=K;++j)f[j]=0; f[0]=dp[u][0]-dp[v][0]; for(int j=1;j<=K;++j)(f[j]+=dp[u][j]-dp[v][j-1]-dp[v][j]+mod*2)%=mod; (dp[v][0]+=f[0])%=mod; for(int j=1;j<=K;++j)(dp[v][j]+=f[j]+f[j-1])%=mod; dfs2(v,u); } } int main(){ n=rd();K=rd();int u,v; for(int i=1;i<n;++i){u=rd();v=rd();add(u,v);} s[0][0]=1; for(int i=1;i<=K;++i){ s[i][1]=1; for(int j=2;j<=i;++j) s[i][j]=(s[i-1][j-1]+s[i-1][j]*j)%mod; } jie[0]=1; for(int i=1;i<=K;++i)jie[i]=jie[i-1]*i%mod; dfs(1,0); dfs2(1,0); for(int i=1;i<=n;++i){ int ans=0; for(int j=0;j<=K;++j)(ans+=s[K][j]*jie[j]%mod*dp[i][j]%mod)%=mod; printf("%d\n",ans); } return 0; }