[国家集训队] 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;
}
posted @ 2022-09-28 21:13  Smallbasic  阅读(30)  评论(0)    收藏  举报