分层期望 DP
P4321 随机漫游 - 洛谷
给定一张 \(n\) 个点 \(m\) 条边的无向图。\(T\) 次询问,每次给定整数 \(x\) 与集合 \(S\),从 \(x\) 开始随机游走,问经过 \(S\) 中的所有点的期望步数。
\(n \le 18, T \le 10^5\)
\(n \le 18\),一眼状压:设 \(f(u, S)\) 表示当前在节点 \(u\),还有集合 \(S\) 内的节点没有访问,需要的期望次数。
\(X - Y\) 表示属于集合 \(X\) 但不属于集合 \(Y\) 的元素组成的集合,也就是:\(\{ x | x \in X \and x \notin Y\}\)。那么 \(S - \{v\}\) 就是从 \(S\) 中除掉 \(v\)。
显然这个转移是有环的(\(S - \{v\}\) 可能为 \(S\)),考虑高斯消元就直接爆了。
那就要考虑优化高斯消元,注意到 \(S\) 转移到的集合要么是 \(S\),要么集合大小小于 \(S\)(小集合转移到大集合)。这样我们就可以对 \(S\) 进行分层,按集合大小从小到大进行 DP,这样就可以把环缩小到 \(n\) 的级别(未知量只有 \(f(1, S) \sim f(n, S)\)),再进行高斯消元就可以接受了。
\(O(1)\) 查询答案即可。时间复杂度:\(O(2^nn^3)\),可以进行很多常数优化,跑到 \(0.7s\) 以内。
- 高斯消元消成上三角,而不是对角,然后会带,能减少 \(\frac{1}{2}\) 的常数。
- 注意到如果 \(u \in S\),\(f(u, S)\) 其实没有意义,减小矩阵大小。
这样就优化了 \(10\) 倍常数。
int main() {
int n; cin >> n;
int ans = 0;
for (int i = 1; i < (1 << n); i++) {
int k = 0;
for (int j = 0; j < n; j++) {
k += (((i >> j) & 1) ^ 1);
}
ans += k * k * (k + 1) / 2;
}
cout << ans; // n = 18, ans = 122680314
}
[PKUWC2018] 随机游走 - 洛谷 P5643
这个是树上的版本。众所周知,树上的高斯消元是可以通过从叶子开始将 \(f_u\) 表示为 \(kf_{fa} + b\) 的形式,然后求出根的 DP 值递推一遍做到线性的。这个题也是一样的,只不过求逆元需要花费一个 \(\log\),使用常数极小的 exgcd 有极大优化。
时间复杂度:\(O(2^nn\log V)\)。
浙公网安备 33010602011771号