HDU - 4625 JZPTREE(第二类斯特林数+树DP)
https://vjudge.net/problem/HDU-4625
题意
给出一颗树,边权为1,对于每个结点u,求sigma(dist(u,v)^k)。
分析
贴个官方题解
n^k并不好转移,于是用第二类斯特林数转化一下,这样可以预处理第二类斯特林数,而sigma(C(dist(u,v),i))则利用C(n,x)=C(n-1,x)+C(n-1,x-1)来进行树DP转移得到。
设dp[u][k]=sigma(C(dist(u,v),k)),则dp[u][k]=dp[v][k]+dp[v][k-1],这里v是u的儿子。先dfs一次算dp值。
接下来再dfs一次,每次以u为根,计算Eu,注意转移时需要将子结点作为新的根,此时需要计算一下合适的dp值。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <ctime> #include <vector> #include <queue> #include <map> #include <stack> #include <set> #include <bitset> using namespace std; typedef long long ll; typedef unsigned long long ull; #define ms(a, b) memset(a, b, sizeof(a)) #define pb push_back #define mp make_pair #define pii pair<int, int> #define IOS ios::sync_with_stdio(0);cin.tie(0); #define random(a, b) rand()*rand()%(b-a+1)+a #define pi acos(-1.0) const ll INF = 0x3f3f3f3f3f3f3f3fll; const int inf = 0x3f3f3f3f; const int maxn = 5e4+10; const int maxm = 1e5+10; const int mod = 10007; struct edge{ int t,n; edge(int t=0,int n=0): t(t),n(n){} }e[maxn<<1]; int head[maxn],tot; void addedge(int u,int v){ e[++tot]=edge(v,head[u]),head[u]=tot; e[++tot]=edge(u,head[v]),head[v]=tot; } int n,k; int s[550][550],fac[550]; void init(){ s[0][0]=fac[0]=1; for(int i=1;i<550;i++){ fac[i]=fac[i-1]*i%mod; for(int j=1;j<550;j++){ s[i][j]=(j*s[i-1][j]+s[i-1][j-1])%mod; } } for(int i=1;i<550;i++) for(int j=1;j<550;j++) s[i][j]=s[i][j]*fac[j]%mod; } int dp[maxn][550]; void pre_dfs(int u,int p){ dp[u][0]=1; for(int i=1;i<=k;i++) dp[u][i]=0; for(int i=head[u];~i;i=e[i].n){ int v = e[i].t; if(v!=p){ pre_dfs(v,u); for(int j=0;j<=k;j++){ dp[u][j]+=dp[v][j]; if(j) dp[u][j]+=dp[v][j-1]; dp[u][j]%=mod; } } } } int ans[maxn]; void dfs(int u,int p){ ans[u]=0; for(int i=0;i<=k;i++) ans[u]=(ans[u]+s[k][i]*dp[u][i])%mod; for(int i=head[u];~i;i=e[i].n){ int v=e[i].t; if(v!=p){ for(int j=0;j<=k;j++){ dp[u][j]+=mod-dp[v][j]; if(j) dp[u][j]+=mod-dp[v][j-1]; dp[u][j]%=mod; } for(int j=0;j<=k;j++){ dp[v][j]+=dp[u][j]; if(j) dp[v][j]+=dp[u][j-1]; dp[v][j]%=mod; } dfs(v,u); for(int j=0;j<=k;j++){ dp[v][j]+=mod-dp[u][j]; if(j) dp[v][j]+=mod-dp[u][j-1]; dp[v][j]%=mod; } for(int j=0;j<=k;j++){ dp[u][j]+=dp[v][j]; if(j) dp[u][j]+=dp[v][j-1]; dp[u][j]%=mod; } } } } int main(){ #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("output.txt", "w", stdout); #endif int t; scanf("%d",&t); init(); while(t--){ tot=0; memset(head,-1,sizeof head); int u,v; scanf("%d%d",&n,&k); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); addedge(u,v); } pre_dfs(1,-1); dfs(1,-1); for(int i=1;i<=n;i++) printf("%d\n",ans[i]); } return 0; }