[国家集训队] Crash 的文明世界

考虑 k 次方十分的难受,我们考虑用第二类斯特林数转化一下。考虑经典式子:

mn=i=0n{ni}(mi)i!

我们有:

i=1ndist(x,i)k=i=1nj=0k{kj}(dist(i,x)j)j!

=j=0k{kj}j!i=1n(dist(i,x)j)

考虑求后面那坨,我们设 f[i][j] 表示 i 的子树中所有节点的 (i的距离j) 的和,对于 i 的每个儿子,它子树中的点到 i 的距离比到它的距离大 1,由加法公式:

f[i][j]=dsonif[d][j]+f[d][j1]

我们要求每一个点为根时的 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 @   Smallbasic  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示