「Luogu4321」随机游走

题目描述

有一张 \(n\) 个点 \(m\) 条边的无向图,\(Q\) 组询问,每次询问给出一个出发点和一个点集 \(S\) ,求从出发点出发随机游走走遍这个点集的期望步数。

\(1 \leq n \leq 18, 1 \leq Q \leq 10^5\)

解题思路 :

听说是 \(\text{pkuwc2018d2t3}\) 加强版?但是原题时限是1s,各种卡不进去感觉一定要写 \(\text{Min-Max}\) 容斥,不过反正我今年听指导建议没报 \(\text{pkuwc}\) ,结果 \(\text{thuwc}\) 没 \(\text{py}\) 上 。

丧心病狂的出题人肯定是要我们 \(O(1)\) 回答询问了,不过感觉暴力还是蛮好想的,网上以前看到有大佬说过期望要倒着推,然后状压一波就出来了。设 \(f(S, u)\) 表示当前已经走遍了点集 \(S\) 接下来走遍全图的期望。这样定义的好处在于终止状态方便表示,直接认为点集外的点已经走过就可以了,如果正着定义走遍点集 \(S\) 的期望的话,终止状态的计算就需要一堆集合再算上对应的概率了。于是显然有

\[f(S, u) = \frac{1}{deg_u} \sum_{edge(u, v)} f(S|v, v) + 1
\]

特别的 \(f(S, i) = 0\) 当 \(S\) 是全集 \(\{1..n\}\) 的时候。

这个式子的转移还有环诶,所以还要高斯消元来解,一眼看上去复杂度是 \(O((n\times2^n)^3)\),复杂度爆炸。

冷静分析一下,并不是所有的转移都会成环,当满足 \(v \notin S\) 的时候,\(S\) 是 \(S|v\) 的真子集,只考虑这样的转移的话转移的形态是一个 \(\text{DAG}\) ,更准确的说是一个分层图。

这启发我们可以来分层求解,把互不相交的环拆开来考虑,而不是一起高斯消元,不妨变换一下转移的式子。

\[f(S, u) = \frac{1}{deg_u} \sum_{edge(u, v), v \notin S} f(S|v, v) + \sum_{edge(u, v), v \in S} f(S, v) + 1
\]

此时成环的转移只有后面那个式子,于是我们可以一层一层计算,对于每一个 \(S\) ,先将前面那个式子的贡献记录在矩阵里面,暴力消元后面那个式子这样每次消元的矩阵大小只有 \(n^2\) 级别,总复杂度优化到 \(O(2^n\times n^3)。\)

另外吐槽一下:我的高斯消元写法好像不加剪枝就被卡常数了,今天做了一天的题没有一道不被卡常,怕是联赛要被卡成暴力分。

/*program by mangoyang*/
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
} const int N = 25, mod = 998244353;
typedef int Matrix[N][N];
vector<int> g[N];
Matrix a; int Ans[(1<<20)+5][N], n, e;
inline void up(int &x, int y){ (x += y) %= mod; }
inline void del(int &x, int y){ x = (x + y >= 0) ? x + y : x + y + mod; }
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline void Gauss(Matrix &a){
int tmp, f;
for(int i = 1; i <= n; i++){
int r = i;
for(int j = i + 1; j <= n; j++) if(a[j][i] > a[i][i]) r = j;
for(int j = i; j <= n + 1; j++) swap(a[i][j], a[r][j]);
if(!a[i][i]) continue;
tmp = Pow(a[i][i], mod - 2);
for(int j = i + 1; j <= n; j++){
f = 1ll * a[j][i] * tmp % mod;
for(int k = i; k <= n + 1; k++)
del(a[j][k], 1ll * -a[i][k] * f % mod);
}
}
for(int i = n; i >= 1; i--){
for(int j = i + 1; j <= n; j++)
del(a[i][n+1], 1ll * -a[j][n+1] * a[i][j] % mod);
a[i][n+1] = 1ll * a[i][n+1] * Pow(a[i][i], mod - 2) % mod;
}
}
int main(){
read(n), read(e);
for(int i = 1, x, y; i <= e; i++)
read(x), read(y), g[x].push_back(y), g[y].push_back(x);
for(int i = 1; i <= n; i++) Ans[(1<<n)-1][i] = 0;
for(int s = (1 << n) - 2; s; s--){
for(int i = 1; i <= n + 1; i++)
for(int j = 1; j <= n + 1; j++) a[i][j] = 0;
for(int i = 1; i <= n; i++) if((1 << i - 1) & s){
int tmp = Pow(g[i].size(), mod - 2);
for(int j = 0; j < g[i].size(); j++){
int v = g[i][j];
if(!((1 << v - 1) & s)) up(a[i][n+1], Ans[s|(1<<v-1)][v]);
else a[i][v] = (-tmp + mod) % mod;
}
a[i][n+1] = 1ll * tmp * a[i][n+1] % mod;
a[i][n+1] = (a[i][n+1] + 1) % mod, a[i][i] = 1;
}
Gauss(a);
for(int i = 1; i <= n; i++) Ans[s][i] = a[i][n+1];
}
int q; read(q);
while(q--){
int num = 0, s, all = (1 << n) - 1; read(num);
for(int i = 1, x; i <= num; i++) read(x), all ^= (1 << x - 1);
read(s), all |= (1 << s - 1), printf("%d\n", Ans[all][s]);
}
return 0;
}

「Luogu4321」随机游走的更多相关文章

  1. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  2. 「PKUWC2018」随机游走(min-max容斥+FWT)

    「PKUWC2018」随机游走(min-max容斥+FWT) 以后题目都换成这种「」形式啦,我觉得好看. 做过重返现世的应该看到就想到 \(min-max\) 容斥了吧. 没错,我是先学扩展形式再学特 ...

  3. LOJ2542. 「PKUWC2018」随机游走

    LOJ2542. 「PKUWC2018」随机游走 https://loj.ac/problem/2542 分析: 为了学习最值反演而做的这道题~ \(max{S}=\sum\limits_{T\sub ...

  4. LOJ #2542「PKUWC2018」随机游走

    $ Min$-$Max$容斥真好用 $ PKUWC$滚粗后这题一直在$ todolist$里 今天才补掉..还要更加努力啊.. LOJ #2542 题意:给一棵不超过$ 18$个节点的树,$ 5000 ...

  5. 「PKUWC2018」随机游走

    题目 我暴力过啦 看到这样的东西我们先搬出来\(min-max\)容斥 我们设\(max(S)\)表示\(x\)到达点集\(S\)的期望最晚时间,也就是我们要求的答案了 显然我们也很难求出这个东西,但 ...

  6. loj2542「PKUWC2018」随机游走

    题目描述 给定一棵 nn 个结点的树,你从点 xx 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 QQ 次询问,每次询问给定一个集合 SS,求如果从 xx 出发一直随机游走,直到点集 SS ...

  7. 【LOJ2542】「PKUWC2018」随机游走

    题意 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次询问给定一个集合 \(S\),求如果从 \(x\) 出发一 ...

  8. loj#2542. 「PKUWC2018」随机游走(树形dp+Min-Max容斥)

    传送门 首先,关于\(Min-Max\)容斥 设\(S\)为一个点的集合,每个点的权值为走到这个点的期望时间,则\(Max(S)\)即为走遍这个集合所有点的期望时间,\(Min(S)\)即为第一次走到 ...

  9. LOJ2542. 「PKUWC2018」随机游走【概率期望DP+Min-Max容斥(最值反演)】

    题面 思路 我们可以把到每个点的期望步数算出来取max?但是直接算显然是不行的 那就可以用Min-Max来容斥一下 设\(g_{s}\)是从x到s中任意一个点的最小步数 设\(f_{s}\)是从x到s ...

随机推荐

  1. 【BZOJ】4872: [Shoi2017]分手是祝愿 期望DP

    [题意]给定n盏灯的01状态,操作第 i 盏灯会将所有编号为 i 的约数的灯取反.每次随机操作一盏灯直至当前状态能够在k步内全灭为止(然后直接灭),求期望步数.n,k<=10^5. [算法]期望 ...

  2. 20155117王震宇 实验三 敏捷开发与XP实践 实验报告

    实验内容 XP基础 XP核心实践 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验.撰写实验报告,实 ...

  3. $this->success()传值不完整

    public function manager_doExport() { $search=$_POST['search']; //前台输入2017-12-1,即,$search['starttime' ...

  4. final关键字详解

    java中,final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量).下面就从这三个方面来了解一下final关键字的基本用法. 1.修饰类 当用final修饰一个类时,表明这个类不能被继承 ...

  5. LintCode之硬币排成线

    输入的n可以分为两种情况: 1. 如果n是3的倍数的话,不论A怎么拿B都可以拿(3-A拿的个数)来使其保持是3的倍数,他就一定能拿到最后一块,所以n是3的倍数的话B必胜 2. 如果n不是3的倍数的话, ...

  6. vc6列表框多选时,获取哪些项被选中

    //vc6列表框多选时,获取哪些项被选中...... void CWebcyzDlg::OnButton2() { int n = m_mylist1.GetSelCount();//首先获取一共有多 ...

  7. Java源码-HashMap(jdk1.8)

    一.hash方法 如下是jdk1.8中的源码 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = ke ...

  8. POJ - Problem 2282 - The Counting Problem

    整体思路:对于每一位,先将当前未达到$limit$部分的段 [如 $0$ ~ $10000$] 直接处理好,到下一位时再处理达到$limit$的部分. · $1 × 10 ^ n$以内每个数(包括$0 ...

  9. 9.Python3标准库--数据压缩与归档

    ''' 尽管现代计算机系统的存储能力日益增长,但生成数据的增长是永无休止的. 无损(lossless)压缩算法以压缩或解压缩数据花费的时间来换取存储数据所需要的空间,以弥补存储能力的不足. Pytho ...

  10. swiper (Table切换和动态加载时候出现的问题)

    本文为让心灵-去旅行原创,转载请说明.. 我们在写一个简单的swiper图片轮播的时候很简单,是写死的也就那么几张图片轮播.如果这时候图片和一些东西是后台的,你从js里动态添加到DOM时,这时候你就会 ...