bzoj 2159 - Crash 的 文明世界

Description

给定一棵\(n\le 10^5\)的树, 和\(k\le 150\)

求每个点\(x\)的$$S(x) = \sum_{y=1}^n dis(x, y) ^ k$$

Analysis

k比较小, 考虑斯特林展开

\[\begin{aligned} S(x) &= \sum_{y=1}^n dis(x, y)^k\\ &=\sum_{y=1}^n \sum_{i=0}^k \left\{\begin{matrix}k\\i\end{matrix}\right\} i!\binom{dis(x,y)}{i}\\ &=\sum_{i=0}^k \left\{\begin{matrix}k\\i\end{matrix}\right\} i! \sum_{y=1}^n \binom{dis(x,y)}{i}\\ \end{aligned} \]

考虑求后面的部分, 可以上下树形dp一下

记$$f[x][i] = \sum_{y\in sub(x)} \binom{dis(x, y)}{i}$$

那么$$f[x][i] = \sum_{y\in son(x)} f[y][i] + [i>0]f[y][i-1]$$

即利用$$\Delta \binom x c = \binom x {c-1}$$

这题只用暴力转移组合数一次

Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define rep(i,a,b) for (int i = (a); i <= (b); ++ i)
#define per(i,a,b) for (int i = (a); i >= (b); -- i)
#define For(i,a,b) for (int i = (a); i < (b); ++ i)
using namespace std;
const int N = 5e4 + 7;
const int M = 157;
const int Q = 10007;

inline int ri(){
	int x = 0; bool f = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
	for (; isdigit(c); c = getchar()) x = x*10+c-48;
	return f ? x : -x;
}

inline int pls(int x, int y) {return (x + y) % Q;}
inline int mns(int x, int y) {return pls(x, Q - y);}
inline int mul(int x, int y) {return x * y % Q;}

int n, m;
int fac[M], S2[M][M];
int f[N][M], g[N][M];
int ans[N];

struct vec {
	int g[N], te;
	struct edge{int y, nxt;}e[N << 1];
	inline void push(int x, int y) {e[++te] = (edge){y, g[x]}; g[x] = te;}
	inline void push2(int x, int y) {push(x, y); push(y, x);}
	inline int& operator () (int x) {return g[x];}
	inline edge& operator [] (int x) {return e[x];}
}e;

void upd(int *A, int *B, int kd = 1) {
	if (kd == 1) {
		rep (i, 0, m) A[i] = pls(A[i], B[i]);
		rep (i, 1, m) A[i] = pls(A[i], B[i-1]);
	}
	if (kd == -1) {
		rep (i, 0, m) A[i] = mns(A[i], B[i]);
		rep (i, 1, m) A[i] = mns(A[i], B[i-1]);
	}
}

void UP(int x, int fa) {
	int p, y;

	rep (i, 0, m) ans[x] = pls(ans[x], mul(S2[m][i], pls(g[x][i], f[x][i])));
	
	for (p=e(x); p; p=e[p].nxt)
	if ((y=e[p].y) != fa) {
		upd(f[x], f[y], -1);

		upd(g[y], f[x]);
		upd(g[y], g[x]);
		UP(y, x);

		upd(f[x], f[y]);
	}
}

void DW(int x, int fa) {
	int p, y;
	for (p=e(x); p; p=e[p].nxt)
	if ((y=e[p].y) != fa) {
		DW(y, x);
		upd(f[x], f[y]);
	}
	f[x][0] = pls(f[x][0], 1); // d(x, x) = 0   
}

void Uncompress() {
	int L, i, now, A, B, mod, tmp;
	scanf("%d%d%d", &n, &m, &L);
	scanf("%d%d%d%d", &now, &A, &B, &mod);
	for (i = 1; i < n; i ++) {
		now = (now * A + B) % mod;
		tmp = (i < L) ? i : L;
		e.push2(i - now % tmp, i + 1);
	}
} 

int main() {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif

	Uncompress();

	int i, j;
	for (fac[0] = 1, i=1; i<=m; ++i) fac[i] = mul(fac[i-1], i);

	for (S2[0][0] = 1, i=1; i<=m; ++i)
	for (j=1; j<=i; ++j) S2[i][j] = pls(mul(j, S2[i-1][j]), S2[i-1][j-1]);
	rep (i, 0, m) rep (j, 0, i) S2[i][j] = mul(S2[i][j], fac[j]);

	DW(1, 0);
	UP(1, 0);

	rep (i, 1, n) printf("%d\n", ans[i]);

	return 0;
}
posted @ 2017-09-22 22:02  _zwl  阅读(284)  评论(0编辑  收藏  举报