背景:
自己的模拟赛自己的防
AK
\text{AK}
AK题防住了自己。
NTT
\text{NTT}
NTT不熟啊。
题目传送门:
https://www.luogu.org/problem/P4827
题意:
一棵树,对于每一个点
x
x
x求:
∑
i
=
1
n
dis
(
x
,
i
)
k
\sum_{i=1}^{n}\text{dis}(x,i)^k
∑i=1ndis(x,i)k。
思路 1 1 1:
显然可以用点分治,时间复杂度:
Θ
(
n
log
n
log
k
)
\Theta(n\log n \log k)
Θ(nlognlogk)。
这差不多是模板题了。
懒人模式,代码就不打了。
思路 2 2 2:
看到这种
k
k
k次方的式子,容易想到伯努利数或者第二类斯特林数。
显然后者应用范围更广。
假设
x
x
x为当前的根。
∑
i
=
1
n
dis
(
x
,
i
)
k
\sum_{i=1}^{n}\text{dis}(x,i)^k
i=1∑ndis(x,i)k
因为 dis ( x , i ) k = ∑ j = 0 k S k , j C dis ( x , i ) j j ! \text{dis}(x,i)^k=\sum_{j=0}^{k}S_{k,j}C_{\text{dis}(x,i)}^jj! dis(x,i)k=∑j=0kSk,jCdis(x,i)jj!,所以有:
= ∑ i = 1 n ∑ j = 0 k S k , j C dis ( x , i ) j j ! =\sum_{i=1}^{n}\sum_{j=0}^{k}S_{k,j}C_{\text{dis}(x,i)}^{j}j! =i=1∑nj=0∑kSk,jCdis(x,i)jj!
= ∑ j = 0 k S k , j j ! ∑ i = 1 n C dis ( x , i ) j =\sum_{j=0}^{k}S_{k,j}j!\sum_{i=1}^{n}C_{\text{dis}(x,i)}^{j} =j=0∑kSk,jj!i=1∑nCdis(x,i)j
= ∑ j = 0 k S k , j j ! ∑ i = 1 n C dis ( x , i ) − 1 j + C dis ( x , i ) − 1 j − 1 =\sum_{j=0}^{k}S_{k,j}j!\sum_{i=1}^{n}C_{\text{dis}(x,i)-1}^{j}+C_{\text{dis}(x,i)-1}^{j-1} =j=0∑kSk,jj!i=1∑nCdis(x,i)−1j+Cdis(x,i)−1j−1
考虑用
dp
\text{dp}
dp来处理
C
dis
(
x
,
i
)
j
C_{\text{dis}(x,i)}^{j}
Cdis(x,i)j,设
f
x
,
j
=
C
dis
(
x
,
i
)
j
f_{x,j}=C_{\text{dis}(x,i)}^{j}
fx,j=Cdis(x,i)j,因为
i
i
i和
i
i
i的儿子的距离差为
1
1
1,因此有转移方程:
f
x
,
j
=
∑
y
∈
i
.
s
o
n
f
y
,
j
+
f
y
,
j
−
1
f_{x,j}=\sum_{y∈i.son}f_{y,j}+f_{y,j-1}
fx,j=y∈i.son∑fy,j+fy,j−1
每一次转移时考虑换根即可。
x
x
x(父亲)转移到
y
y
y(儿子),将
x
x
x在
y
y
y中的贡献减去,再新加入
x
x
x对
y
y
y的新贡献即可。
时间复杂度:
Θ
(
n
k
)
\Theta(nk)
Θ(nk)。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 10007
using namespace std;
int n,k,len,ans;
int last[50010],now[50010],fac[50010],s[160][160],f[50010][160];
struct node{int x,y,next;} a[100010];
void ins(int x,int y)
{
a[++len]=(node){x,y,last[x]}; last[x]=len;
}
void dfs1(int x,int fa)
{
f[x][0]=1;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
dfs1(y,x);
f[x][0]=(f[x][0]+f[y][0])%mod;
for(int j=1;j<=k;j++)
f[x][j]=(f[x][j]+f[y][j]+f[y][j-1])%mod;
}
}
void dfs2(int x,int fa)
{
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
now[0]=(f[x][0]-f[y][0]+mod)%mod;
for(int j=1;j<=k;j++)
now[j]=(f[x][j]-f[y][j]-f[y][j-1]+mod*2)%mod;
f[y][0]=(f[y][0]+now[0])%mod;
for(int j=1;j<=k;j++)
f[y][j]=(f[y][j]+now[j-1]+now[j])%mod;
dfs2(y,x);
}
}
void init()
{
fac[0]=1;
s[0][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]=(s[i-1][j-1]+j*s[i-1][j]%mod)%mod;
}
}
int main()
{
int x,y;
scanf("%d %d",&n,&k);
init();
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
ins(x,y),ins(y,x);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1;i<=n;i++)
{
int tot=0;
for(int j=1;j<=k;j++)
tot=(tot+s[k][j]*fac[j]%mod*f[i][j]%mod)%mod;
printf("%d\n",tot);
}
}