P4827-[国家集训队]Crash 的文明世界【树形dp,换根法,斯特林数】
正題
題目鏈接: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∑n?dis(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∑n?dis(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∑n?dis(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);} }總結
以上是生活随笔為你收集整理的P4827-[国家集训队]Crash 的文明世界【树形dp,换根法,斯特林数】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享一个超好用的系统清理软件好用的清理软
- 下一篇: 有了这个神器,再也不用烦恼远程调用电脑了