P5405 [CTS2019]氪金手游

这应该是CTS2019最简单的题。----lhm

首先假设题目给的是一个单向的链,并且所有 \(W\) 都是确定的,那么显然第一步一定要选择链的起点,概率为 \(\frac{W_1}{S_{1...n}}\);第二步如果选到起点,就再选一次,因此相当于与起点无关,因此合法概率为 \(\frac{W_2}{S_{2...n}}\);第三步合法概率为\(\frac{W_3}{S_{3...n}}\)...

如果给的是一个外向树,我们发现儿子与儿子之间是互不影响的(显然),那么 \(cur\) 子树的合法概率是:\(\sum_{w[...]}\frac{W_{cur}}{Sum[cur]}\prod_{son}f_{son}\),注意这里的\(f_{son}\) 是在 \(son\)\(W\)\(w[son]\) 的条件下的合法概率。

现在我们考虑不同概率的 \(W\)。发现子树内具体的 \(W\) 对父亲的答案没有影响,只有子树的和以及合法概率对答案有影响。因此我们考虑将子树 \(W\) 和计入状态。我们设 \(f[cur][w]\) 表示 \(cur\) 及其子树的 \(W\) 和为 \(w\) 的合法概率,然后可以树形背包解决。于是我们有:

(初始化,算入 \(W_{cur}\) 并设置 \(w\)

\[f[cur][1/2/3]= (1/2/3) * a[1/2/3] \]

(加入一个子树)

\[f[cur][i+j]<-f[cur][i] * f[to][j] \]

(每个 \(cur\) 结束后的操作,意义见上面的式子)

\[f[cur][i] <- f[cur][i] / i \]

现在考虑如果有由儿子指向父亲的边该怎么办。正难则反,既然子树之间无关系,那么我们可以求出忽视这条边的限制(直接“删掉”边“分离”出子树)以及这条边是正向边(同上)的“合法”概率,然后相减。即,对于反向边,有:

\[f[cur][i] <- f[cur][i] * f[to][j] \]

\[f[cur][i + j] <- (-f[cur][i] * f[to][j]) \]

其它不变。

关键代码:

void dfs(int cur, int faa) {
	siz[cur] = 1;
	for (register int i = head[cur]; i; i = e[i].nxt) {
		int to = e[i].to; if (to == faa) continue;
		dfs(to, cur);
		for (register int j = 0; j <= siz[cur] * 3; ++j) {
			for (register int k = 0; k <= siz[to] * 3; ++k) {
				if (i & 1)//son -> father
					ADD(tmp[j], f[cur][j] * f[to][k] % P),
					ADD(tmp[j + k], P - f[cur][j] * f[to][k] % P);
				else//father -> son
					ADD(tmp[j + k], f[cur][j] * f[to][k] % P);
			}
		}
		siz[cur] += siz[to];
		for (register int j = 0; j <= siz[cur] * 3; ++j)
			f[cur][j] = tmp[j], tmp[j] = 0;
	}
	for (register int i = 1; i <= siz[cur] * 3; ++i)
		f[cur][i] = f[cur][i] * inv[i] % P;
}

...

f[i][1] = 1ll * a * inv % P, f[i][2] = 2ll * b * inv % P;
f[i][3] = 3ll * c * inv % P;

一边听课一遍写题解好难受啊

posted @ 2020-08-02 20:28  JiaZP  阅读(73)  评论(0编辑  收藏  举报