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

发布时间 2024-01-07 16:38:56作者: 小超手123

题意:

给定一个 \(n\) 个点的树,对于每个点 \(u\),求 \(\sum_{v=1}^{n}(d_{u,v})^k\)

\(n \le 5 \times 10^4,k \le 150\)

分析:

一道思路很自然的数学题。

利用第二类斯特林数转化式子:

\[\begin{aligned} \sum_{v=1}^{n}(d_{u,v})^k &= \sum_{v=1}^{n} \sum_{j=0}^{k}j!\binom{d_{u,v}}{j}\begin{Bmatrix}k\\j\end{Bmatrix} \\&= \sum_{j=0}^{k}j!\begin{Bmatrix}k\\j\end{Bmatrix}\sum_{v=1}^{n}\binom{d_{u,v}}{j} \end{aligned} \]

考虑使用树形 dp 计算 \(\sum_{v=1}^{n}\binom{d_{u,v}}{j}\) 这一部分。

当以 \(u\) 为根时,记

\[f_{x,j}=\sum_{y \in subtree(x)}\binom{d_{x,y}}{j} \]

如何转移呢?

由于 \(d_{fa,y}-1=d_{fa,x}\),考虑拆组合数

\[\binom{d_{x,y}}{j}=\binom{d_{x,y}-1}{j-1}+\binom{d_{x,y}-1}{j} \]

那么转移就很明显了

\[f_{x,j}=\sum_{y \in son_{x}} f_{y,j}+f_{y,j-1} \]

可是这样只能处理以 \(u\) 为根的答案,考虑换根 dp。

\(ans_{u,i}\) 表示以 \(u\) 为根 dp 时 \(f_{u,i}\) 的值。

考虑根从 \(fa\) 移到 \(x\) 的过程,\(ans_{u,i}=f_{u,i}+z_{i}-z_{i-1}\)\(z_{i}\) 表示以 \(u\) 为根 dp 时 \(f_{fa,i}\) 的值。

\(z_{i}\) 也很容易得到,\(z_{i}=ans_{fa,i}-f_{x,i}-f_{x,i-1}\)

时间复杂度 \(O(nk)\)

代码:

#include <bits/stdc++.h>
#define int long long
#define mod 10007
#define N 50004
#define M 160
using namespace std;
int n, k, res;
vector<int>p[N];
int f[N][M], ans[N][M], fac[N], h[N][M], z[N];
void init() {
	h[0][0] = 1;
	for(int i = 1; i <= k; i++)
	for(int j = 1; j <= i; j++) h[i][j] = (h[i - 1][j - 1] + h[i - 1][j] * j % mod) % mod;
	fac[0] = 1;
	for(int i = 1; i <= M; i++) fac[i] = fac[i - 1] * i % mod;
}

void dfs(int x, int fa) {
	f[x][0] = 1;
	for(auto y : p[x]) {
		if(y == fa) continue;
		dfs(y, x);
		f[x][0] = (f[x][0] + f[y][0]) % mod; 
		for(int i = 1; i <= k; i++) f[x][i] = (f[x][i] + f[y][i] + f[y][i - 1]) % mod;
	}
}
void Get(int x, int fa) {
	for(int i = 0; i <= k; i++) ans[x][i] = f[x][i];
	if(fa) {
		for(int i = 1; i <= k; i++) z[i] = (ans[fa][i] - f[x][i] - f[x][i - 1] + mod + mod) % mod;
		z[0] = (ans[fa][0] - f[x][0] + mod) % mod;
		for(int i = 1; i <= k; i++) ans[x][i] = (ans[x][i] + z[i] + z[i - 1]) % mod;
		ans[x][0] = (ans[x][0] + z[0]) % mod;
	}
	

	for(auto y : p[x]) {
		if(y == fa) continue;
		Get(y, x);
	}
}
signed main() {
	cin >> n >> k;
	init();
	for(int i = 1, u, v; i < n; i++) {
		cin >> u >> v;
		p[u].push_back(v);
		p[v].push_back(u);
	}
	dfs(1, 0);
	Get(1, 0);
	for(int u = 1; u <= n; u++) {
		
		res = 0;
		for(int i = 0; i <= k; i++) res = (res + h[k][i] * fac[i] % mod * ans[u][i] % mod) % mod;
		cout << res << endl;
	}
    return 0;
}