题意
给定一棵 n 点的树,定义 (dis(u,v)) 为树上路径长度。对于每个点,定义 (E_u=sum_{v=1}^n dis(u,v)^k) ,其中 k 为给定数。
求每个 (E_imod 10007 (i=1sim n)) .
思路
求幂可以考虑转化成第二类斯特林数。有公式: (x^n = sum_{k=0}^n egin{Bmatrix} n \ k end{Bmatrix} x^{underline{k}}.)
从而 (E_u = sum_{v=1}^n (dis(u, v))^k = sum_{i=0}^k egin{Bmatrix} k \ i end{Bmatrix} sum_{v=1}^n (dis(u, v))^{underline{i}}.)
令 (f[u][k] = sum_{v in T_u} (dis(u, v))^{underline{k}},) (T_u) 为 (u) 为根的子树,且显然有 ((x+1)^{underline{k}} = x^{underline{k}}+kx^{underline{k-1}})
考虑求 (f[u][k].)
[f[u][k]=sum_{vin T_u} dis(u,v)^{underline{k}}
=sum_{vin son(u)}sum_{win T_v}[dis(v,w)+1]^{underline{k}}
]
这时候就可以运用上述公式。
[f[u][k]=sum_{vin son(u)}sum_{win T_v} [dis(v,w)^{underline{k}}+k imes dis(v,w)^{underline{k-1}}]
]
回到 (f[u][k]) 的定义,可得到转移方程
[f[u][k]=sum_{vin son(u)} f[v][k]+k imes f[v][k-1]
]
两遍 DFS 即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+10,K=510,mod=10007;
int n,k,S[N][K],f[N][K],g[N][K];
vector<int> v[N];
void dfs1( int x,int fa )
{
f[x][0]=1;
for ( int i=1; i<=k; i++ ) f[x][i]=0;
for ( auto y : v[x] )
{
if ( y==fa ) continue;
dfs1( y,x );
f[x][0]=(f[x][0]+f[y][0])%mod;
for ( int i=1; i<=k; i++ )
f[x][i]=( f[x][i]+(f[y][i]+i*f[y][i-1]))%mod;
}
}
void dfs2( int x,int fa )
{
if ( !fa ) for ( int i=0; i<=k; i++ ) g[x][i]=f[x][i];
for ( auto y : v[x] )
{
if ( y==fa ) continue;
g[y][0]=g[x][0];
for ( int i=1; i<=k; i++ )
{
int t1=(g[x][i]-(f[y][i]+i*f[y][i-1]))%mod;
int t2=( g[x][i-1]-( f[y][i-1]+(i-1)*(i-2>=0 ? f[y][i-2] : 0) ))%mod;
g[y][i]=( f[y][i]+( t1+i*t2) )%mod;
}
dfs2( y,x );
}
}
void init()
{
S[0][0]=1;
for ( int i=1; i<=500; i++ )
for ( int j=1; j<=i; j++ )
S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%mod;
}
int main()
{
int T; scanf( "%d",&T ); init();
while ( T-- )
{
scanf( "%d%d",&n,&k );
for ( int i=1; i<=n; i++ )
v[i].clear();
for ( int i=1,x,y; i<n; i++ )
scanf( "%d%d",&x,&y ),v[x].push_back(y),v[y].push_back(x);
dfs1( 1,0 ); dfs2( 1,0 );
for ( int x=1;x<=n; x++ )
{
int res=0;
for ( int i=0; i<=k; i++ )
res=( res+S[k][i]*g[x][i])%mod;
printf( "%d
",(res+mod)%mod );
}
}
}