CF1097G Vladislav and a Great Legend(第二类斯特林数 + 树形依赖背包)

Description

给定一棵有 n n n 个点的树。对于这棵树的非空节点集合 S S S,令 f ( S ) f(S) f(S) 表示包含 S S S 中所有节点的最小联通子树的边数。给定 k k k,你需要求

∑ ∅ ≠ S ⊆ [ 1 , n ] f ( S ) k \sum_{\emptyset \neq S \subseteq [1,n] }f(S)^{k} =S[1,n]f(S)k

2 ≤ n ≤ 1 0 5 , 1 ≤ k ≤ 200 2 \leq n \leq 10^{5}, 1 \leq k \leq 200 2n105,1k200

Solution

当指数比较大时,通常考虑用斯特林数的性质把 f ( S ) k f(S)^k f(S)k 变成

∑ i = 0 k ( f ( S ) i ) S ( k , i ) × i ! \sum_{i=0}^{k}{f(S) \choose i} S(k, i) \times i! i=0k(if(S))S(k,i)×i!

那么原式为

∑ ∅ ≠ S ⊆ [ 1 , n ] ∑ i = 0 k ( f ( S ) i ) S ( k , i ) × i ! = ∑ i = 0 k i ! × S ( k , i ) × ∑ ∅ ≠ S ⊆ [ 1 , n ] ( f ( S ) i ) \sum_{\emptyset \neq S \subseteq [1,n] } \sum_{i=0}^{k}{f(S) \choose i} S(k, i) \times i! \\ = \sum_{i=0}^{k} i! \times S(k, i) \times \sum_{\emptyset \neq S \subseteq [1,n] }{f(S) \choose i} =S[1,n]i=0k(if(S))S(k,i)×i!=i=0ki!×S(k,i)×=S[1,n](if(S))

外层可以枚举,并用递推式预处理斯特林数。考虑内层在树上的意义:对于每个非空点集的生成树,求在树中标记 i i i 条边的方案数。我们可以转换成,选一棵标记了 i i i 条边的非空点集的生成树的方案数。这个可以树上背包,设 f x , i f_{x,i} fx,i 为以 x x x 为根的子树的答案。将 x x x 的儿子一个个插入 x x x 中,假设要插入 y y y,那么分类讨论

  • 答案在 x x x 的子树中。
  • 答案在 y y y 的子树中,可能有一条连向 x x x 的边,也可能没有。
  • 答案由 x x x 的子树和 y y y 的子树构成,可能有一条连向 x x x 的边,也可能没有。

第三点就是树上背包,枚举的范围需要和 k k k 取个 min,不然会被卡。在树形 dp 的时候,在每棵生成树上深度最浅的点也就是 x x x 统计答案,这样就不重不漏了。时间复杂度 O ( n k 2 ) O(nk^2) O(nk2)

女少口β可

Code

void dfs(int x, int fa) {
    
    
	sz[x] = 1, f[x][0] = 1;
	for (int i = head[x]; i; i = e[i].nxt) {
    
    
		int y = e[i].to;
		if (y != fa) {
    
    
			dfs(y, x);
			memeset(g, 0, sizeof(g));
			for (int j = 1; j <= min(k, size[y]); j++) //case 2
				g[j] = add(g[j], add(f[y][j], f[y][j - 1]));
			g[0] = add(g[0], f[y][0]); //case 2
			for (int j = 0; j <= min(k, size[x]); j++) //case 3
				for (int k = 0; k <= min(k - j, size[y]); k++) {
    
    
					int z = f[x][j] * f[y][k] % p;
					g[j + k] = add(g[j + k], val);
					g[j + k + 1] = add(g[j + k + 1], val);
					ans[j + k] = add(ans[j + k], val);
					ans[j + k + 1] = add(ans[j + k + 1], val);
				}
		}
		for (int j = 0; j <= k; j++) f[x][j] += g[j];
	}
}

猜你喜欢

转载自blog.csdn.net/qq_39984146/article/details/107848254
今日推荐