题面


思路

我们可以把到每个点的期望步数算出来取max?但是直接算显然是不行的

那就可以用Min-Max来容斥一下

设\(g_{s}\)是从x到s中任意一个点的最小步数

设\(f_{s}\)是从x到s中任意一个点的最大步数

然后就可以的得到

\(f_{s}=\sum_{t\subseteq s}(-1)^{|t|+1}g_t\)

然后考虑g怎么求

设\(p_i\)是i点到任意一个子集中的点的最小步数

有\(p_u=\frac{1}{du_u}(1+p_{fa_u})+\frac{1}{du_u}\sum_{v\in child_u}(p_v+1)\)

然后我们令\(p_u=a_up_{fa_u}+b_u\)

很显然有\(p_u=\frac{1}{du_u}\sum(a_vf_u+b_v+1)+\frac{1}{du_u}(p_{fa_u})\)

然后移项可以得到\(a_u=\frac{1}{du_u-\sum a_v},b_u=\frac{\sum(b_v+1)+1}{du_u-\sum a_v}\)

然后因为x是根没有父亲,所以\(g_{s}=(bitcnt(s) \& 1)?b_u:-b_u\)

然后就可以用子集前缀和进行累加了

最后直接输出答案就可以了


#include <bits/stdc++.h>

using namespace std;

const int Mod = 998244353;
const int N = 20; int n, m, x;
int a[N], b[N], du[N];
int f[1 << N];
vector<int> g[N]; int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
function<int(int a, int b)> add = [&](int a, int b) {
return (a += b) >= Mod ? a - Mod : a;
}; function<int(int a, int b)> sub = [&](int a, int b) {
return (a -= b) < 0 ? a + Mod : a;
}; function<int(int a, int b)> mul = [&](int a, int b) {
return (long long) a * b % Mod;
}; function<int(int a, int b)> fast_pow = [&](int a, int b) {
int res = 1;
for (; b; b >>= 1, a = mul(a, a))
if (b & 1) res = mul(res, a);
return res;
}; function<int(int a)> bitcnt = [&](int a) {
int res = 0;
for (; a; a >>= 1)
if (a & 1) ++res;
return res;
}; function<void(int u, int fa, int s)> dfs = [&](int u, int fa, int s) {
if ((s >> (u - 1)) & 1) return;
a[u] = du[u], b[u] = (u == x) ? 0 : 1; // x不用向fa走的1
for (auto v : g[u]) {
if (v == fa) continue;
dfs(v, u, s);
a[u] = sub(a[u], a[v]);
b[u] = add(b[u], b[v] + 1);
}
a[u] = fast_pow(a[u], Mod - 2);
b[u] = mul(b[u], a[u]);
}; scanf("%d %d %d", &n, &m, &x);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
++du[u], ++du[v];
}
int up = (1 << n) - 1;
for (int s = 1; s <= up; s++) {
for (int i = 1; i <= n; i++)
a[i] = b[i] = 0;
dfs(x, 0, s);
f[s] = (bitcnt(s) & 1) ? b[x] : (Mod - b[x]) % Mod;
}
f[0] = 0;
for (int i = 1; i <= n; i++) { // 这个循环在外面
for (int s = 1; s <= up; s++) {
if ((s >> (i - 1)) & 1) {
f[s] = add(f[s], f[s ^ (1 << (i - 1))]);
}
}
}
while (m--) {
int num, cur, s = 0;
scanf("%d", &num);
while (num--) {
scanf("%d", &cur);
s |= 1 << (cur - 1);
}
printf("%d\n", f[s]);
}
return 0;
}

LOJ2542. 「PKUWC2018」随机游走【概率期望DP+Min-Max容斥(最值反演)】的更多相关文章

  1. loj2542 「PKUWC2018」随机游走 【树形dp + 状压dp + 数学】

    题目链接 loj2542 题解 设\(f[i][S]\)表示从\(i\)节点出发,走完\(S\)集合中的点的期望步数 记\(de[i]\)为\(i\)的度数,\(E\)为边集,我们很容易写出状态转移方 ...

  2. LOJ2542. 「PKUWC2018」随机游走

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

  3. loj2542「PKUWC2018」随机游走

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

  4. loj2542 「PKUWC2018」随机游走 MinMax 容斥+树上高斯消元+状压 DP

    题目传送门 https://loj.ac/problem/2542 题解 肯定一眼 MinMax 容斥吧. 然后问题就转化为,给定一个集合 \(S\),问期望情况下多少步可以走到 \(S\) 中的点. ...

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

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

  6. LOJ2540. 「PKUWC2018」随机算法【概率期望DP+状压DP】

    LINK 思路 首先在加入几个点之后所有的点都只有三种状态 一个是在独立集中,一个是和独立集联通,还有一个是没有被访问过 然后前两个状态是可以压缩起来的 因为我们只需要记录下当前独立集大小和是否被访问 ...

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

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

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

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

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

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

随机推荐

  1. c语言中的0UL或1UL是什么意思

    0UL 表示 无符号长整型 0 1UL 表示 无符号长整型 1 如果不写UL后缀,系统默认为:int, 即,有符号整数. 1.数值常数有:整型常数.浮点常数:2.只有数值常数才有后缀说明:3.数值常数 ...

  2. HDU 6106 Classes

    Classes 思路:a中包含的元素:只参加a的,只参加a且b的,只参加a且c的,只参加a且b且c的: b中包含的元素:只参加b的,只参加a且b的,只参加b且c的,只参加a且b且c的: c中包含的元素 ...

  3. C#复制文件

    string pLocalFilePath ="";//要复制的文件路径 string pSaveFilePath ="";//指定存储的路径 if (File ...

  4. centos系统lvm的安装

    今天安装redhat6.1在分区时提示”可引导分区不能位于逻辑卷上“,原来linux的引导区不能放在逻辑卷上. 解决方法: 1.先建立一个物理分区划给/boot分区 2.剩下的空间划给lvm. 然后开 ...

  5. ORACLE COMMENTON 使用

    oracle中用comment on命令给表或字段加以说明,语法如下:COMMENT ON  { TABLE [ schema. ]    { table | view }  | COLUMN [ s ...

  6. 在linux环境下编译C++ 程序

    单个源文件生成可执行程序 下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码: 单个源文件生成可执行程序 /* helloworld.cpp */ #include ...

  7. Thrift0.11.0基于Intellij IDEA的简单的例子

    前言 目前流行的服务调用方式有很多种,例如基于 SOAP 消息格式的 Web Service,基于 JSON 消息格式的 RESTful 服务等.其中所用到的数据传输方式包括 XML,JSON 等,然 ...

  8. PowerDesigner16工具学习笔记-工具介绍

    1.初始界面 1.1 .浏览窗口:本地(Local)浏览窗口.知识库(Repository)浏览窗口 Local:用于显示本地模型 Repository:用于显示知识库模型 1.2 .输出窗口:用于显 ...

  9. dp入门求最大公共子序列

    #include "bits/stdc++.h" using namespace std; ],b[]; ][]; int main() { cin >> a > ...

  10. Animation鱼眼效果

    <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head>    < ...