[BZOJ2159]Crash 的文明世界(第二类斯特林数 + 树形 DP)

Address

Solution

  • 好久没写博客了,来水一篇
  • 发现一个困难: d i s t ( i , j ) k dist(i,j)^k 没有可加性
  • 换句话说, ( d i s t ( i , j ) + 1 ) k (dist(i,j)+1)^k 不能用仅含 d i s t ( i , j ) k dist(i,j)^k 的式子表示出来
  • 使用二项式定理展开 ( d i s t ( i , j ) + 1 ) k (dist(i,j)+1)^k ,可以做到 O ( n k 2 ) O(nk^2) 的优秀复杂度,拿到 50 50 分的优秀得分
  • 考虑等式
  • i k = j { k j } × ( i j ) × j ! i^k=\sum_j\begin{Bmatrix}k\\j\end{Bmatrix}\times\binom ij\times j!
  • 证明右转 蒟蒻的博客
  • 其中 { n m } \begin{Bmatrix}n\\m\end{Bmatrix} 为第二类斯特林数,即 n n 个元素划分成 m m 个无序非空集合的方案数, ( n m ) \binom nm 为组合数 ,即 n n 个元素中选出 m m 个无序元素的方案数
  • 把式子化一下
  • j = 1 n d i s t ( i , j ) k = j = 1 n h = 0 k { k h } × ( d i s t ( i , j ) h ) × h ! \sum_{j=1}^ndist(i,j)^k=\sum_{j=1}^n\sum_{h=0}^k\begin{Bmatrix}k\\h\end{Bmatrix}\times\binom{dist(i,j)}h\times h!
  • = h = 0 k { k h } × h ! × j = 1 n ( d i s t ( i , j ) h ) =\sum_{h=0}^k\begin{Bmatrix}k\\h\end{Bmatrix}\times h!\times\sum_{j=1}^n\binom{dist(i,j)}h
  • 于是我们要求的就是对于每个 1 u n 1\le u\le n 0 i k 0\le i\le k ,求
  • v = 1 n ( d i s t ( u , v ) i ) \sum_{v=1}^n\binom{dist(u,v)}i
  • 我们的状态出来了
  • f [ u ] [ i ] f[u][i] 表示 u u u u 的子树内的所有点的距离,的 ( d i s t i ) \binom{dist}i 之和
  • 根据优美的组合数公式 ( n m ) = ( n 1 m ) + ( n 1 m 1 ) \binom nm=\binom{n-1}m+\binom{n-1}{m-1} 得到
  • f [ u ] [ i ] = v s u b s t r e e [ u ] ( d i s t ( u , v ) i ) f[u][i]=\sum_{v\in substree[u]}\binom{dist(u,v)}i
  • = v s u b s t r e e [ u ] ( ( d i s t ( u , v ) 1 i ) + ( d i s t ( u , v ) 1 i 1 ) ) =\sum_{v\in substree[u]}(\binom{dist(u,v)-1}i+\binom{dist(u,v)-1}{i-1})
  • = [ i = 0 ] + v s o n [ u ] ( f [ v ] [ i ] + f [ v ] [ i 1 ] ) =[i=0]+\sum_{v\in son[u]}(f[v][i]+f[v][i-1])
  • 然而我们要求的不仅仅是源点为 1 1 的答案,故我们还需要换根
  • g [ u ] [ i ] g[u][i] 表示 u u 到整棵树除了 u u 的子树之外的所有点的距离,的 ( d i s t i ) \binom{dist}i 之和
  • 转移和 f f 差不多,注意计算 g [ f a t h e r [ u ] ] g[father[u]] 时需要消除 f [ u ] f[u] 的影响
  • 复杂度 O ( n k ) O(nk) 非常优秀

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Tree(u) for (int e = adj[u], v; e; e = nxt[e]) if ((v = go[e]) != fu)

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

const int N = 5e4 + 5, M = N << 1, E = 155, ZZQ = 10007;

int n, k, ecnt, nxt[M], adj[N], go[M], f[N][E], g[N][E], S[E][E], fac[E];

void add_edge(int u, int v)
{
	nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
	nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}

void dfs1(int u, int fu)
{
	int i;
	f[u][0] = 1;
	Tree(u)
	{
		dfs1(v, u);
		f[u][0] += f[v][0];
		For (i, 1, k)
			f[u][i] = (f[u][i] + f[v][i] + f[v][i - 1]) % ZZQ;
	}
}

void dfs2(int u, int fu)
{
	int i;
	For (i, 0, k)
	{
		int tmp = (g[u][i] + (i ? g[u][i - 1] : 0)) % ZZQ;
		Tree(u) tmp = (tmp + f[v][i] + (i ? f[v][i - 1] : 0)) % ZZQ;
		Tree(u) g[v][i] = (tmp - f[v][i] - (i ? f[v][i - 1] : 0)
			+ ZZQ + ZZQ + (!i)) % ZZQ;
	}
	Tree(u) dfs2(v, u);
}

int main()
{
	int i, j, x, y, L, now, A, B, Q;
	n = read(); k = read(); L = read(); now = read(); A = read();
	B = read(); Q = read();
	For (i, 1, n - 1)
	{
		now = (now * A + B) % Q;
		int tmp = i < L ? i : L;
		x = i - now % tmp; y = i + 1;
		add_edge(x, y);
	}
	S[0][0] = fac[0] = 1;
	For (i, 1, k) fac[i] = 1ll * fac[i - 1] * i % ZZQ;
	For (i, 1, k) For (j, 1, i)
		S[i][j] = (S[i - 1][j - 1] + j * S[i - 1][j]) % ZZQ;
	dfs1(1, 0); dfs2(1, 0);
	For (i, 1, n)
	{
		int ans = 0;
		For (j, 0, k)
			ans = (S[k][j] * fac[j] % ZZQ * (f[i][j]
				+ g[i][j] + (j ? g[i][j - 1] : 0)) + ans) % ZZQ;
		printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/85016525