记得去年暑假集训的时候本来想了一个动态点分的做法的,然后写道一半因为某些不知名原因就没写了,然后就一直放着,然后发现斯特林反演真NM好写
首先考虑用关于幂的斯特林反演:
\[m^n=\sum_{i=0}^m \left\{ ^n_i\right\}\times i!\times C_m^i\]
套上去就是:
\[ans(x)=\sum_{i=1}^n dis(i,x)^k\]
\[=\sum_{i=1}^n \sum_{j=0}^k \left\{ ^k_j\right\}\times C_{dis(i,x)}^j\times j!\]
\[=\sum_{j=0}^k \left\{ ^k_j\right\}\times j!\times \sum_{i=1}^n C_{dis(i,x)}^j\]
显然我们现在只要知道\(\sum_{i=1}^n C_{dis(i,x)}^j\)怎么求即可,设:
\[dn_{x,i}=\sum_{y\in x} C_{dis(x,y)}^i\]
\[up_{x,i}=\sum_{y\not \in x} C_{dis(x,y)}^i\]
其中\(y\in x\)表示\(y\)在\(x\)子树内
显然我们可以推出关于\(dn\)的方程:
\[dn_{x,i}=\sum_{y\in x} C_{dis(x,y)}^i\]
\[=[i=0]+\sum_{v\in son(x)}\sum_{y\in v} C_{dis(v,y)+1}^i\]
\[=[i=0]+\sum_{v\in son(x)}\sum_{y\in v} C_{dis(v,y)}^i+C_{dis(v,y)}^{i-1}\]
\[=[i=0]+\sum_{v\in son(x)} dn_{v,i}+dn_{v,i-1}\]
那么接下来就是\(up\)的,如果熟悉换根DP那一套的话会很容易推出来,注意要容斥掉一部分:
\[up_{x,i}=\sum_{y\not \in x} C_{dis(x,y)}^i\]
\[=\sum_{y\not \in fa(x)} C_{dis(fa(x),y)+1}^i+\sum_{y\in fa(x)} C_{dis(fa(x),y)+1}^i-\sum_{y\in x} C_{dis(x,y)+2}^i\]
\[=up_{fa(x),i}+up_{fa(x),i-1}+dn_{fa(x),i}+dn_{fa(x),i-1}-dn_{x,i}-2\times dn_{x,i-1}-dn_{x,i-2}\]
边界就是\(up_{1,i}=0\)
然后就做完了,复杂度\(O(nk)\)
PS:BZOJ上又要改输入又会莫名挂掉,因此下面的代码是Luogu上的同题的
#include<cstdio> #define RI register int #define CI const int& using namespace std; const int N=500005,M=155,mod=10007; struct edge { int to,nxt; }e[N<<1]; int n,head[N],cnt,k,x,y,fact[N],S[M][M],up[N][M],dn[N][M],ans; inline void addedge(CI x,CI y) { e[++cnt]=(edge){y,head[x]}; head[x]=cnt; e[++cnt]=(edge){x,head[y]}; head[y]=cnt; } inline int fix(int x) { while (x<0) x+=mod; while (x>=mod) x-=mod; return x; } inline void init(CI n) { RI i,j; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod; for (S[0][0]=i=1;i<=n;++i) for (j=0;j<=i;++j) S[i][j]=fix((j?S[i-1][j-1]:0)+1LL*j*S[i-1][j]%mod); } #define to e[i].to inline void DFS1(CI now=1,CI fa=0) { dn[now][0]=1; for (RI i=head[now],j;i;i=e[i].nxt) if (to!=fa) for (DFS1(to,now),j=0;j<=k;++j) dn[now][j]=fix(dn[now][j]+(j?dn[to][j-1]:0)+dn[to][j]); } inline void DFS2(CI now=1,CI fa=0) { RI i; if (now!=1) { for (i=0;i<=k;++i) up[now][i]=fix(up[fa][i]+(i?up[fa][i-1]:0)+dn[fa][i]+(i?dn[fa][i-1]:0)-dn[now][i]-2*(i?dn[now][i-1]:0)-(i>=2?dn[now][i-2]:0)); } for (i=head[now];i;i=e[i].nxt) if (to!=fa) DFS2(to,now); } #undef to int main() { RI i,j; for (scanf("%d%d",&n,&k),i=1;i<n;++i) scanf("%d%d",&x,&y),addedge(x,y); for (init(k),DFS1(),DFS2(),i=1;i<=n;++i) { for (ans=0,j=0;j<=k;++j) ans=fix(ans+1LL*fact[j]*S[k][j]%mod*(up[i][j]+dn[i][j])%mod); printf("%d\n",ans); } return 0; }
来源:https://www.cnblogs.com/cjjsb/p/12240707.html