题目大意
给出一个(n)个点的树,和常数(k),对于(forall iin[1,n]),求出:
[sum_{j=1}^{n} ext{dist}(i,j)^k
]
(nle 5 imes 10^4,kle 150)
思路
真的很妙,一开始完全没有思路,看了( exttt{y2823774827y})的题解之后瞬间懂了。
我们考虑对于(i)如何计算答案,我们发现这个指数非常不好看,于是我们可以使用第二类斯特林数展开,就跟组合数问题差不多的,变为:
[sum_{j=1}^{n}sum_{d=0}^{ ext{dist}(i,j)}inom{ ext{dist}(i,j)}{d}egin{Bmatrix}k\dend{Bmatrix}d!
]
交换求和顺序可以得到:
[=sum_{d=0}^{min(n,k)}egin{Bmatrix}k\dend{Bmatrix}d!sum_{j=1}^{n}inom{ ext{dist}(i,j)}{d}
]
于是,我们的问题就是如何快速求出后面那个(sum)。我们想到这个东西可以拆成:
[inom{ ext{dist}(i,j)}{d}=inom{ ext{dist}(i,j)-1}{d}+inom{ ext{dist}(i,j)-1}{d-1}
]
于是,我们用换根(dp)解决这个问题了。具体见代码。
( exttt{Code})
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 50005
#define mod 10007
#define MAXM 155
int qkpow (int a,int b){
int res = 1;for (;b;b >>= 1,a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod;
return res;
}
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
struct edge{
int v,nxt;
}e[MAXN << 1];
int top = 1,head[MAXN];
void Add_Edge (int u,int v){
e[++ top] = edge {v,head[u]},head[u] = top;
e[++ top] = edge {u,head[v]},head[v] = top;
}
int n,k,S[MAXM][MAXM],fac[MAXM],dp1[MAXN][MAXM],dp2[MAXN][MAXM],tmp[MAXM];
//dp1[u][k]表示的是sum_{j在i的子树内(包括i)} inom{dist(i,j)}{k}
//dp2[u][k]表示的是sum_{j=1}^{n} inom{dist(i,j)}{k}
void dfs1 (int u,int fa){
dp1[u][0] = 1;
for (Int i = head[u];i;i = e[i].nxt){
int v = e[i].v;
if (v == fa) continue;
dfs1 (v,u);
for (Int j = 1;j <= k;++ j) dp1[u][j] = add (dp1[u][j],add (dp1[v][j],dp1[v][j - 1]));
dp1[u][0] = add (dp1[u][0],dp1[v][0]);
}
}
void dfs2 (int u,int fa){//换根dp
for (Int i = 0;i <= k;++ i) dp2[u][i] = dp1[u][i];
if (fa){
for (Int i = 1;i <= k;++ i) tmp[i] = dec (dp2[fa][i],add (dp1[u][i],dp1[u][i - 1]));
tmp[0] = dec (dp2[fa][0],dp1[u][0]);
for (Int i = 1;i <= k;++ i) dp2[u][i] = add (dp2[u][i],add (tmp[i],tmp[i - 1]));
dp2[u][0] = add (dp2[u][0],tmp[0]);
}
for (Int i = head[u];i;i = e[i].nxt){
int v = e[i].v;
if (v == fa) continue;
dfs2 (v,u);
}
}
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
signed main(){
read (n,k),S[0][0] = fac[0] = 1;
for (Int i = 1;i <= k;fac[i] = mul (i,fac[i - 1]),++ i)
for (Int j = 1;j <= i;++ j)
S[i][j] = add (S[i - 1][j - 1],mul (j,S[i - 1][j]));
for (Int i = 2,u,v;i <= n;++ i) read (u,v),Add_Edge (u,v);
dfs1 (1,0),dfs2 (1,0);
for (Int i = 1;i <= n;++ i){
int sum = 0;
for (Int j = 0;j <= k;++ j) sum = add (sum,mul (fac[j],mul (S[k][j],dp2[i][j])));
write (sum),putchar ('
');
}
return 0;
}