正题
题目链接:https://www.luogu.com.cn/problem/P4827
题目大意
一颗nnn个点的树,定义dis(i,j)dis(i,j)dis(i,j)表示树上i,ji,ji,j两点的距离,对于每个iii求∑j=1ndis(i,j)m\sum_{j=1}^ndis(i,j)^mj=1∑ndis(i,j)m
解题思路
根据斯特林数的性质我们有
nm=∑k=0m{mk}(nk)k!n^m=\sum_{k=0}^m\begin{Bmatrix}m\\k\end{Bmatrix}\binom{n}{k}k!nm=k=0∑m{mk}(kn)k!
那么就有
dis(i,j)m=∑k=0m{mk}(dis(i,j)k)k!dis(i,j)^m=\sum_{k=0}^m\begin{Bmatrix}m\\k\end{Bmatrix}\binom{dis(i,j)}{k}k!dis(i,j)m=k=0∑m{mk}(kdis(i,j))k!
也就是要求
∑j=1ndis(i,j)m=∑j=1n(∑k=0m{mk}(dis(i,j)k)k!)\sum_{j=1}^ndis(i,j)^m=\sum_{j=1}^n(\sum_{k=0}^m\begin{Bmatrix}m\\k\end{Bmatrix}\binom{dis(i,j)}{k}k!)j=1∑ndis(i,j)m=j=1∑n(k=0∑m{mk}(kdis(i,j))k!)
⇒∑j=1ndis(i,j)m=∑k=0m{mk}k!∑j=1n(dis(i,j)k)\Rightarrow\sum_{j=1}^ndis(i,j)^m=\sum_{k=0}^m\begin{Bmatrix}m\\k\end{Bmatrix}k!\sum_{j=1}^n\binom{dis(i,j)}{k}⇒j=1∑ndis(i,j)m=k=0∑m{mk}k!j=1∑n(kdis(i,j))
考虑树形dpdpdp计算后面的贡献,设fx,jf_{x,j}fx,j表示以111为根,在xxx的子树中在(dis1,yj)\binom{dis_{1,y}}{j}(jdis1,y)的值和。可以根据(nm)=(n−1m−1)+(n−1m)\binom{n}{m}=\binom{n-1}{m-1}+\binom{n-1}{m}(mn)=(m−1n−1)+(mn−1)可以O(nk)O(nk)O(nk)求出
然后根据转移方程换根求其他点为根的答案。
时间复杂度O(nk)O(nk)O(nk)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5e4+10,K=170,XJQ=10007;
struct node{int to,next;
}a[N*2];
int n,m,tot,S[N][K],fac[K];
int f[N][K],g[N][K],ls[N];
void init(){S[0][0]=S[1][1]=fac[0]=1;for(int i=1;i<=m;i++)fac[i]=fac[i-1]*i%XJQ;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)(S[i][j]=S[i-1][j-1]+j*S[i-1][j]%XJQ)%=XJQ;return;
}
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
void dfs(int x,int fa){f[x][0]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;dfs(y,x);for(int j=1;j<=m;j++)(f[x][j]+=f[y][j]+f[y][j-1])%=XJQ;(f[x][0]+=f[y][0])%=XJQ;}return;
}
int k(int x,int j,int fa)
{return (g[fa][j]-f[x][j]-(j?f[x][j-1]:0)+2*XJQ)%XJQ;}
void dp(int x,int fa){for(int j=1;j<=m;j++)g[x][j]=(k(x,j,fa)+k(x,j-1,fa))%XJQ;g[x][0]=k(x,0,fa)+1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;for(int j=1;j<=m;j++)(g[x][j]+=f[y][j]+f[y][j-1])%=XJQ;(g[x][0]+=f[y][0])%=XJQ;}for(int i=ls[x];i;i=a[i].next)if(a[i].to!=fa)dp(a[i].to,x);return;
}
int main()
{scanf("%d%d",&n,&m);init();for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}dfs(1,1);for(int i=0;i<=m;i++)g[1][i]=f[1][i];for(int i=ls[1];i;i=a[i].next)dp(a[i].to,1);for(int i=1;i<=n;i++){int ans=0;for(int j=0;j<=m;j++)(ans+=S[m][j]*fac[j]%XJQ*g[i][j]%XJQ)%=XJQ;printf("%d\n",ans);}
}