题目大意: 给出一棵树,对于每个 i ∈ [ 1 , n ] i\in[1,n] i∈[1,n],求出 S ( i ) = ∑ j = 1 n d i s ( i , j ) k S(i)=\sum_{j=1}^n dis(i,j)^k S(i)=∑j=1ndis(i,j)k。
题解
看到
k
k
k 次方就能想到要用第二类斯特林数来展开了(不会的话可以参考这里)。那么有:
S
(
i
)
=
∑
d
=
0
k
S
(
k
,
d
)
d
!
∑
j
=
1
n
C
d
i
s
(
i
,
j
)
d
S(i)=\sum_{d=0}^{k} S(k,d)d!\sum_{j=1}^n C_{dis(i,j)}^d
S(i)=d=0∑kS(k,d)d!j=1∑nCdis(i,j)d
前面的 S S S 可以 O ( k 2 ) O(k^2) O(k2) 预处理出来,循环的大小也只有 k k k,也就是说,如果能求出后面的 ∑ j = 1 n C d i s ( i , j ) d \sum_{j=1}^n C_{dis(i,j)}^d ∑j=1nCdis(i,j)d,那么就可以 O ( n , k ) O(n,k) O(n,k) 求出所有 S ( i ) S(i) S(i) 了。
这个东西可以考虑比较套路的二次dp,第一次求出 i i i 的子树内的 j j j 的贡献,第二次再求出 i i i 的父亲节点那边的 j j j 的贡献,然后加起来得到 ∑ j = 1 n C d i s ( i , j ) d \sum_{j=1}^n C_{dis(i,j)}^d ∑j=1nCdis(i,j)d。
为了方便,不妨假定 j ∈ i j\in i j∈i 表示 j j j 在 i i i 的子树内。然后设 d o w n i , d = ∑ j ∈ i C d i s ( i , j ) d , u p i , d = ∑ j ∉ i C d i s ( i , j ) d down_{i,d}=\sum\limits_{j\in i} C_{dis(i,j)}^d,up_{i,d}=\sum\limits_{j\not\in i}C_{dis(i,j)}^d downi,d=j∈i∑Cdis(i,j)d,upi,d=j∈i∑Cdis(i,j)d。
第一次dp求出
d
o
w
n
down
down,对于点
x
x
x,假设
y
y
y 是
x
x
x 的儿子,那么有:
d
o
w
n
x
,
d
=
∑
y
∑
z
∈
y
C
d
i
s
(
y
,
z
)
+
1
d
=
∑
y
∑
z
∈
y
C
d
i
s
(
y
,
z
)
d
+
C
d
i
s
(
y
,
z
)
d
−
1
=
∑
y
d
o
w
n
y
,
d
+
d
o
w
n
y
,
d
−
1
\begin{aligned} down_{x,d}&=\sum\limits_{y}\sum\limits_{z\in y}C_{dis(y,z)+1}^d\\ &=\sum\limits_{y}\sum\limits_{z\in y}C_{dis(y,z)}^d+C_{dis(y,z)}^{d-1}\\ &=\sum\limits_{y}down_{y,d}+down_{y,d-1} \end{aligned}
downx,d=y∑z∈y∑Cdis(y,z)+1d=y∑z∈y∑Cdis(y,z)d+Cdis(y,z)d−1=y∑downy,d+downy,d−1
然后第二次dp求出
u
p
up
up,设
f
a
fa
fa 是
x
x
x 的父亲节点,那么有:
u
p
x
,
d
=
∑
y
∉
f
a
C
d
i
s
(
f
a
,
y
)
+
1
d
+
∑
y
∈
f
a
C
d
i
s
(
f
a
,
y
)
+
1
d
−
∑
y
∈
x
C
d
i
s
(
x
,
y
)
+
2
d
\begin{aligned} up_{x,d}=\sum_{y\not\in fa}C_{dis(fa,y)+1}^d+\sum_{y\in fa} C_{dis(fa,y)+1}^d-\sum_{y\in x}C_{dis(x,y)+2}^d \end{aligned}
upx,d=y∈fa∑Cdis(fa,y)+1d+y∈fa∑Cdis(fa,y)+1d−y∈x∑Cdis(x,y)+2d
其中,第一个 ∑ \sum ∑ 求的是 x x x 的父亲的祖先那边的贡献,第二个和第三个求的是在 f a fa fa 的子树内但不在 x x x 的子树内的点的贡献。
像上面那样展开,就能得到:
u
p
x
,
d
=
u
p
f
a
,
d
+
u
p
f
a
,
d
−
1
+
d
o
w
n
f
a
d
+
d
o
w
n
f
a
,
d
−
1
−
d
o
w
n
x
,
d
−
2
d
o
w
n
x
,
d
−
1
−
d
o
w
n
x
,
d
−
2
up_{x,d}=up_{fa,d}+up_{fa,d-1}+down_{fa_d}+down_{fa,d-1}-down_{x,d}-2down_{x,d-1}-down_{x,d-2}
upx,d=upfa,d+upfa,d−1+downfad+downfa,d−1−downx,d−2downx,d−1−downx,d−2
于是 d o w n down down 和 u p up up 就求出来了。
代码如下:
#include <cstdio>
#define maxn 50010
#define maxk 160
#define mod 10007
int n,k;
struct edge{int y,next;};
edge e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
int S[maxn][maxk],down[maxn][maxk],up[maxn][maxk],fac[maxk];
void dfs1(int x,int fa)
{
down[x][0]=1;
for(int i=first[x];i;i=e[i].next)
if(e[i].y!=fa)
{
dfs1(e[i].y,x);down[x][0]=(down[x][0]+down[e[i].y][0])%mod;
for(int j=1;j<=k;j++)
down[x][j]=(down[x][j]+down[e[i].y][j]+down[e[i].y][j-1])%mod;
}
}
void dfs2(int x,int fa)
{
if(fa)
{
up[x][0]=(up[fa][0]+down[fa][0]-down[x][0]+mod)%mod;
up[x][1]=(up[fa][1]+up[fa][0]+down[fa][1]+down[fa][0]-down[x][1]-2*down[x][0]+3*mod)%mod;
for(int i=2;i<=k;i++)up[x][i]=(up[fa][i]+up[fa][i-1]+down[fa][i]+down[fa][i-1]-down[x][i]-2*down[x][i-1]-down[x][i-2]+4*mod)%mod;
}
for(int i=first[x];i;i=e[i].next)
if(e[i].y!=fa)dfs2(e[i].y,x);
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1,x,y;i<n;i++)scanf("%d %d",&x,&y),
buildroad(x,y),buildroad(y,x);
dfs1(1,0);dfs2(1,0);S[0][0]=1;fac[0]=1;
for(int i=1;i<=k;i++)
{
fac[i]=fac[i-1]*i%mod;
for(int j=1;j<=i;j++)
S[i][j]=(j*S[i-1][j]+S[i-1][j-1])%mod;
}
for(int i=1;i<=n;i++)
{
int tot=0;
for(int j=1;j<=k;j++)
tot=(tot+fac[j]*S[k][j]%mod*((down[i][j]+up[i][j])%mod)%mod)%mod;
printf("%d\n",tot);
}
}