题意

给出一棵树和一个常数 $m$ ,对于每一个 $i~(1\leq i\leq n)$ ,求 $\sum_{j=1}^n\text{dist}(i,j)^m$

题解

关于斯特林数有性质 $x^n=\sum_{i=1}^n\frac{x!}{(x-i)!}\begin{Bmatrix}n\\i\end{Bmatrix}$ ,组合意义相当于枚举非空盒。

则原题有,

$$\sum_{k=1}^m\begin{Bmatrix}m\\k\end{Bmatrix}k!\sum_{j=1}^n\binom{\text{dist}(i,j)}{k} $$

通过树形 DP 求后面的和式。令 $d_{u,i}$ 表示当上面的 $k=i$ 时子树对 $u$ 的贡献, $\text{up}_{u,i}$ 表示除了 $u$ 子树外的节点对 $u$ 的贡献。

代码

const int N = 5e4 + 5, M = 205, mod = 1e4 + 7;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, m;
	int head[N], tot;
	struct Edge {
		int to, nxt;
	} e[N << 1];
	void add_edge (int u, int v) {
		e[++tot] = (Edge) {v, head[u]}, head[u] = tot;
	}
	int fac[N], s[M][M];
	int up[N][M], d[N][M];
	void dfs1 (int u, int fa) {
		d[u][0] = 1;
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (v == fa) continue;
			dfs1 (v, u);
			d[u][0] += d[v][0];
			for (int k = 1; k <= m; k++) 
				d[u][k] = (d[u][k] + d[v][k] + d[v][k - 1]) % mod;
		}
	}
	void dfs2 (int u, int fa) {
		if (fa) {
			up[u][0] = n - d[u][0];
			for (int k = 1; k <= m; k++) {
				up[u][k] = (up[u][k] + up[fa][k] + up[fa][k - 1]) % mod;
				up[u][k] = (up[u][k] + d[fa][k] + d[fa][k - 1]) % mod;
				up[u][k] = (up[u][k] - d[u][k] - d[u][k - 1]) % mod;
				up[u][k] = (up[u][k] - d[u][k - 1]) % mod;
				if (k > 1) up[u][k] = (up[u][k] - d[u][k - 2]) % mod;
				up[u][k] = (up[u][k] + mod) % mod;
			}
		}
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (v == fa) continue;
			dfs2 (v, u);
		}
	}
	int main () {
		n = Read(), m = Read();
		for (int i = 1; i < n; i++) {
			int u = Read(), v = Read();
			add_edge(u, v), add_edge(v, u);
		}
		s[0][0] = fac[0] = 1;
		for (int i = 1; i <= m; i++) {
			fac[i] = fac[i - 1] * i % mod;
			for (int j = 1; j <= i; j++)
				s[i][j] = (s[i - 1][j] * j % mod + s[i - 1][j - 1]) % mod;
		}
		dfs1(1, 0), dfs2(1, 0);
		for (int i = 1; i <= n; i++) {
			int ans = 0;
			for (int k = 1; k <= m; k++) ans = (ans + 1ll * s[m][k] * fac[k] % mod * (up[i][k] + d[i][k]) % mod) %mod;
			printf ("%d\n", ans);
		}
		return 0;
	}
}

int main () {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。