[国家集训队] Crash 的文明世界
考虑 \(k\) 次方十分的难受,我们考虑用第二类斯特林数转化一下。考虑经典式子:
\[m^n=\sum_{i=0}^n \begin{Bmatrix} n \\ i\end{Bmatrix} \binom{m}{i}i!
\]
我们有:
\[\sum_{i=1}^n dist(x,i)^k=\sum_{i=1}^n \sum_{j=0}^k \begin{Bmatrix} k\\j \end{Bmatrix} \binom{dist(i,x)}{j}j!
\]
\[=\sum_{j=0}^k \begin{Bmatrix} k\\j \end{Bmatrix} j! \sum_{i=1}^n \binom{dist(i,x)}{j}
\]
考虑求后面那坨,我们设 \(f[i][j]\) 表示 \(i\) 的子树中所有节点的 \(\binom{\text{到}i\text{的距离}}{j}\) 的和,对于 \(i\) 的每个儿子,它子树中的点到 \(i\) 的距离比到它的距离大 \(1\),由加法公式:
\[f[i][j]=\sum_{d\in son_i} f[d][j]+f[d][j-1]
\]
我们要求每一个点为根时的 \(f\),换根即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5, mod = 10007;
int f[N][155], S[505][505], ans[N][155], fac[155];
struct edge {
int head, to, nxt;
} ed[N << 1];
int en = 0, n, k;
inline void addedge(int from, int to) {
ed[++en].to = to; ed[en].to = to; ed[en].nxt = ed[from].head; ed[from].head = en;
}
inline void dfs(int now, int fa) {
f[now][0] = 1;
for (int i = ed[now].head; i; i = ed[i].nxt) {
int v = ed[i].to;
if (v == fa) continue;
dfs(v, now);
f[now][0] = (f[now][0] + f[v][0]) % mod;
for (int j = 1; j <= k; ++j)
f[now][j] = (f[now][j] + f[v][j] + f[v][j - 1]) % mod;
}
}
inline void dfs2(int now, int fa) {
for (int i = 0; i <= k; ++i) ans[now][i] = f[now][i];
for (int i = ed[now].head; i; i = ed[i].nxt) {
int v = ed[i].to;
if (v == fa) continue;
f[now][0] -= f[v][0];
if (f[now][0] < 0) f[now][0] += mod;
for (int j = 1; j <= k; ++j) {
f[now][j] -= f[v][j] + f[v][j - 1];
f[now][j] %= mod;
if (f[now][j] < 0) f[now][j] += mod;
}
f[v][0] += f[now][0];
if (f[v][0] >= mod) f[v][0] -= mod;
for (int j = 1; j <= k; ++j)
f[v][j] = (f[v][j] + f[now][j] + f[now][j - 1]) % mod;
dfs2(v, now);
f[v][0] -= f[now][0];
if (f[v][0] < 0) f[v][0] += mod;
for (int j = 1; j <= k; ++j) {
f[v][j] = (f[v][j] - f[now][j] - f[now][j - 1]) % mod;
if (f[v][j] < 0) f[v][j] += mod;
}
f[now][0] += f[v][0];
if (f[now][0] >= mod) f[now][0] -= mod;
for (int j = 1; j <= k; ++j)
f[now][j] = (f[now][j] + f[v][j] + f[v][j - 1]) % mod;
}
}
inline int read() {
register int s = 0; register char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
return s;
}
int main() {
n = read(); k = read();
fac[0] = 1;
for (int i = 1; i <= k; ++i) fac[i] = (1ll * i * fac[i - 1]) % mod;
for (int i = 1, u, v; i < n; ++i) {
u = read(); v = read();
addedge(u, v); addedge(v, u);
} dfs(1, 0); dfs2(1, 0);
S[0][0] = 1;
for (int i = 1; i <= k; ++i) {
S[i][0] = 0;
for (int j = 1; j <= k; ++j)
S[i][j] = (S[i - 1][j - 1] + j * S[i - 1][j]) % mod;
}
for (int i = 1; i <= n; ++i) {
int as = 0;
for (int j = 0; j <= k; ++j) {
as += (1ll * ((1ll * S[k][j] * fac[j]) % mod) * ans[i][j]) % mod;
if (as >= mod) as -= mod;
} printf("%d\n", as);
}
return 0;
}

浙公网安备 33010602011771号