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

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

题目大意:如同\([POI2008] STA-Station\),不过求每个点\(\sum\limits_{j = 1}^{n}dis(i,j)^k\)

Solution

太诡了

\[x^n = \sum\limits_{i=1}^{n}\begin{Bmatrix}n \\i \end{Bmatrix}\cdot A_x^i \]

考虑一个组合意义证明,就是给\(n\)个格子染\(x\)种色的方案数,等于先把这\(n\)个格子分成若干集合,在\(x\)个颜色中选出相同个数的颜色,每个集合染一种颜色(排列)的方案数。

然后将排列数转化为可以应用帕斯卡定理的组合数

\[x^n = \sum\limits_{i=1}^{n}\begin{Bmatrix}n \\i \end{Bmatrix}\cdot i!\cdot\binom{x}{i} \]

然后我们就将题目给出的式子转化

\[\sum\limits_{j=1}^{n}dis(i,j)^k=\sum\limits_{j=1}^{n} \sum_{m=1}^{k}\begin{Bmatrix}k \\m \end{Bmatrix}\cdot m!\cdot\binom{dis(i,j)}{m}=\sum\limits_{m=1}^{k}\begin{Bmatrix}k \\m \end{Bmatrix}\cdot m!\sum\limits_{j=1}^{n}\binom{dis(i,j)}{m} \]

第二类斯特林数的递推公式

将p个物体划分成k个非空的不可辨别的集合的方法数。

\[\begin{Bmatrix}n \\x \end{Bmatrix} =\begin{Bmatrix}n-1 \\x \end{Bmatrix} \cdot x + \begin{Bmatrix}n-1 \\x-1 \end{Bmatrix} \]

树形DP

\(d[x,i]\)表示当上面的\(k=i\)\(x\)的子树对\(x\)的贡献,\(u[x,i]\)表示除了\(x\)子树外的节点对\(x\)的贡献。

  1. \(d[x][j] = (d[x][j] + d[e[i].to][j - 1] + d[e[i].to][j])\)

  2. \(u[x][m] = (u[x][m] + u[fa][m] + u[fa][m-1])\)
    \(u[x][m] = (u[x][m] + d[fa][m] + d[fa][m-1])\)
    $ u[x][m] = (u[x][m] - d[x][m] - d[x][m - 1]) \( \)u[x][m] = (u[x][m] - d[x][m - 1]-d[x][m - 2])$

\(u\)加上父亲结点的所有,减去的分别是\(x\)的子树对\(u[fa,m]\)\(up[fa,m-1]\)的贡献。

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 5e4 + 10;
const int M = N << 1;
const int Mod = 10007;

int n, K, ecnt;
int head[N], fac[N];
int s2[N][200], d[N][200], u[N][200], ans[N];

struct Edge{
	int to, next;
}e[M];

inline void adde(int x, int y) {
	e[++ecnt].to = y;
	e[ecnt].next = head[x];
	head[x] = ecnt;
}

inline int read() {
	int w = 0, f = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		w = (w << 3) + (w << 1) + (c ^ 48);
		c = getchar();
	}
	return w * f;
}

void dfs1(int x, int fa) {
	d[x][0] = 1;//实质上是size
	for(int i = head[x]; i; i = e[i].next) {
		if(e[i].to != fa) {
			dfs1(e[i].to, x);
			d[x][0] = (d[x][0] + d[e[i].to][0]) % Mod;//加上子节点的size 
			for(int j = 1; j <= K; ++j) {
				d[x][j] = (d[x][j] + d[e[i].to][j - 1] + d[e[i].to][j]) % Mod;//更新子树内的 
			}			
		}
	} 
}

void dfs2(int x, int fa) {		
	u[x][0] = n - d[x][0];//所有节点减去子树内的 
	if(fa) {
        for (int m = 1; m <= K; ++m) {
            u[x][m] = (u[x][m] + u[fa][m] + u[fa][m-1]) % Mod; 
            u[x][m] = (u[x][m] + d[fa][m] + d[fa][m-1]) % Mod;
            u[x][m] = (u[x][m] - d[x][m] - d[x][m - 1]) % Mod;
            u[x][m] = (u[x][m] - d[x][m - 1]) % Mod;
            if(m > 1) u[x][m] = (u[x][m] - d[x][m - 2]) % Mod;
            u[x][m] = (u[x][m] + Mod) % Mod;
        }
	} 
	for(int i = head[x]; i; i = e[i].next)
		if(e[i].to != fa) dfs2(e[i].to, x);
	return;
}

int main() {
	cin >> n >> K;
	for(int i = 1, la, lb; i <= n - 1; ++i) {
		la = read(), lb = read();
		adde(la, lb);
		adde(lb, la);
	}
	s2[1][1] = 1;
	for(int i = 2; i <= K; ++i)
		for(int j = 1; j <= K; ++j) {
						s2[i][j] = ((s2[i - 1][j] * j) % Mod + s2[i - 1][j - 1]) % Mod;
		}
	fac[1] = 1;
	for(int i = 2; i <= K; ++i){
		fac[i] = (fac[i - 1] * i) % Mod;		
	}

	dfs1(1, 0);
	dfs2(1, 0);
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= K; ++j) {
			ans[i] = (ans[i] + (s2[K][j] % Mod * fac[j] % Mod) % Mod * (d[i][j] + u[i][j]) % Mod) % Mod;
		}
		printf("%d\n", ans[i] % Mod);
	}

		
	return 0;
}
posted @ 2018-09-20 14:43  LMSH7  阅读(250)  评论(2编辑  收藏  举报