分层期望 DP

P4321 随机漫游 - 洛谷

给定一张 \(n\) 个点 \(m\) 条边的无向图。\(T\) 次询问,每次给定整数 \(x\) 与集合 \(S\),从 \(x\) 开始随机游走,问经过 \(S\) 中的所有点的期望步数。

\(n \le 18, T \le 10^5\)

\(n \le 18\),一眼状压:设 \(f(u, S)\) 表示当前在节点 \(u\),还有集合 \(S\) 内的节点没有访问,需要的期望次数。

\[\begin{aligned} f(u, S) = \frac{\sum\limits_{v \in E(u)} f(v, S - \{v\})}{d_u} + 1 \\ d_u \cdot f(u, S) = \sum\limits_{v \in E(u)} f(v, S - \{v\}) + d_u \end{aligned} \]

\(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 有极大优化。

\[d_u \cdot f(u, S) = \sum\limits_{v \in son(u)} f(v, S - \{v\}) + f(fa, S - \{fa\}) + d_u \]

时间复杂度:\(O(2^nn\log V)\)

posted @ 2026-01-07 09:41  xiehanrui0817  阅读(22)  评论(0)    收藏  举报