( ext{Solution:})
要用到的恒等式:
考虑化式子:
上面那个式子是直接默认 (mleq dis(i,j)) 了。
一个细节: 第二类斯特林数的定义是划分成非空集合。
所以才可以像上面的式子一样取 (min.)
接下来观察一下后面的 (C_{dis(i,j)}^k) 可以理解成从一条路径中选择 (k) 条边的方案数。那这个就可以 (dp) 了。
设 (f_{i,j}) 表示子树 (i) 中 到 (i) 的路径 选择 (j) 条边的方案数。这里之所以是到 (i) 的路径,是因为题目中给的式子是 (dis(i,j)) 从而我们可以把 (i) 当根做。
于是乎,尝试写出 (dp) 式子:
意义就是:这条路径上选的边是不是一起选上边 ((v,j).)
于是这个 (dp) 在上述枚举边界的限制下可以做到 (O(nk))
那么现在只求出了一个点对应的 (Ans(i)) 怎么办?考虑大力换根:
观察一下,换根的套路一定是从根的孩子换到爹上面。考虑这样造成的影响:
对于要换上去的根 (x) 来说,贡献分成两部分:一部分是第一次 (dp) 时那棵树中它作为子树的部分;另一部分就是除它之外的部分。而注意到除它之外的部分除了它爹的子树外,还包括和它一起作为其父亲子树的部分。
那就考虑怎么把贡献换上去吧:选择了 (i) 条边,对应需要统计:
-
换下去的 (fa) 作为其子树,它们之间的连边选不选:(g_{fa,i-1}+g_{fa,i})
-
统计原树中和它一同作为父亲子树的点的答案: (f_{fa,i}+f_{fa,i-1})
-
容斥掉多余的答案:对 (f_{fa,i}) 多余的部分是 (f_{x,i}+f_{x,i-1},) 对于 (f_{fa,i-1}) 多余的部分是 (f_{x,i-1}+f_{x,i-2})
考虑到这三步,做一个换根就好了。还有一个细节:对换根十分不熟悉的菜鸡我写的时候直接就继承了 (g_{fa}) 的信息,但实际上是错误的:
主要原因在于,我脑海中想象的换根是已经把 (fa) 换上去了,而这时 (x) 就对应仅次于根的一棵树。但实际上并不是这样:如果是那样,完全不需要考虑 (f_{fa}) 的情况,因为和它同级别的子树其实也就等同于除去它之外的所有点了;但实际上并非如此,换根的时候我们并没有更新所有节点的 (f,) 这也意味着这个想法是错误的,实际上我们的树还是原来的模样,我们已经统计出了 (fa) 作为根的时候的信息,现在来考虑用原来树上的信息来更新出 (x) 作为根的信息。所以,我们需要在原树上进行分析,从而得出上述的结论,不能只凭脑子思考,不画图,这样很容易犯错。
统计出了 (fa) 作为根的答案实际上是有很多用处的,比如会发现它其实保留了 (x) 在原树中的结构;所以这上面很多信息其实是正确的,其他错误的信息也只是有一部分需要进行转移。
继承了 (g_{fa}) 之后思考的就应当是 (x) 当根和现在情况的影响:除了 (x) 子树内的点,到 (x) 的距离都加了 (1.)
这一部分考虑在继承的 (g_{fa}) 上面完成:可以先把之前的 (f_{fa}) 累加进去。因为这一部分在继承的时候是没有改变距离的,因为继承的时候根是父亲。
那么这样一加实际上又加多了,减去原来的部分就是算出 (f_x) 对 (f_{fa}) 的贡献。
至于其他的部分,继承的时候稍微处理一下就行了。
至于斯特林数直接递推公式大力 (O(k^2)) 处理即可。
总复杂度 (O(nk+k^2) o O(nk).)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
const int mod=10007;
inline int Add(int x,int y){return (x+y)%mod;}
inline int Mul(int x,int y){return 1ll*x*y%mod;}
inline int dec(int x,int y){return (x-y+mod)%mod;}
int S[200][200],n,k,f[N][200],g[N][200];
int head[N],tot,Ans[N],fac[N];
inline int Min(int x,int y){return x<y?x:y;}
inline int Max(int x,int y){return x>y?x:y;}
struct E{int nxt,to;}e[N];
inline void add(int x,int y){
e[++tot]=(E){head[x],y};
head[x]=tot;
}
inline int qpow(int a,int b){
int res=1;
while(b){
if(b&1)res=Mul(res,a);
a=Mul(a,a);b>>=1;
}
return res;
}
void Spre(){
S[0][0]=S[1][1]=1;
for(int i=2;i<=k;++i)
for(int j=1;j<=i;++j)
S[i][j]=Add(S[i-1][j-1],Mul(j,S[i-1][j]));
fac[0]=1;
for(int i=1;i<=n;++i)fac[i]=Mul(fac[i-1],i);
}
void dfs(int x,int fa){
f[x][0]=1;
for(int i=head[x];i;i=e[i].nxt){
int j=e[i].to;
if(j==fa)continue;
dfs(j,x);
for(int v=1;v<=k;++v)f[x][v]=Add(f[x][v],Add(f[j][v],f[j][v-1]));
f[x][0]=Add(f[x][0],f[j][0]);
}
}
void change(int x,int fa){
if(fa){
for(int i=0;i<=k;++i){
if(i==0)g[x][i]=Add(g[fa][0],Add(f[fa][0],mod-f[x][0]));
else if(i==1)g[x][i]=Add(g[fa][i],Add(g[fa][i-1],Add(f[fa][i],Add(f[fa][i-1],Add(mod-f[x][i],mod-f[x][i-1]+mod-f[x][i-1])))));
else {
g[x][i]=Add(g[fa][i],Add(g[fa][i-1],Add(f[fa][i],Add(f[fa][i-1],Add(mod-f[x][i],mod-f[x][i-1]+mod-f[x][i-1])))));
g[x][i]=Add(g[x][i],mod-f[x][i-2]);
}
}
}
for(int i=head[x];i;i=e[i].nxt){
int j=e[i].to;
if(j==fa)continue;
change(j,x);
}
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
Spre();
dfs(1,0);change(1,0);
for(int i=1;i<=n;++i){
int Ans=0;
for(int j=0;j<=k;++j){
int v=Mul(fac[j],S[k][j]);
Ans=Add(Ans,Mul(v,f[i][j]+g[i][j]));
}
printf("%d
",Ans);
}
return 0;
}