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;
一边听课一遍写题解好难受啊