题目描述

  有一棵 \(n\) 个点的树。你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去。

  有 \(q\) 次询问,每次询问给定一个集合 \(S\),求如果从 \(x\) 出发一直随机游走,直到点集 \(S\) 中所有点都至少经过一次的话,期望游走几步。

  特别地,点 \(x\)(即起点)视为一开始就被经过了一次。

  答案对 \(998244353\) 取模。

题解

  这道题要求点集 \(S\) 中所有点都至少经过一次的期望步数,直接做不好做,要先用一个 min-max 容斥转换成走到点集 \(S\) 中第一个点的期望步数:

\[\max(S)=\sum_{T\subseteq S,T\neq \varnothing}{(-1)}^{|T|+1}\min(T)
\]

  然后就可以列方程高斯消元了。

  \(f_i\) 表示从 \(i\)走到最近的点所需要的最小步数。

\[\begin{align}
f_i&=1+\frac{1}{d_i}f_{fa}+\frac{1}{d_i}\sum_v f_v
\end{align}
\]

  直接高斯消元是 \(O(n^3)\) 的,但是我们可以用一些技巧把这个过程加速到 \(O(n\log p)\)(\(\log p\) 来自求逆元)。

  设 \(f_i=a_if_{fa}+b_i\)。特别的,如果 \(i\in S\),那么\(a_i=0,b_i=0\)。

\[\begin{align}
f_i&=1+\frac{1}{d_i}f_{fa}+\frac{1}{d_i}\sum_{v}(a_vf_i+b_v)\\
&=1+\frac{1}{d_i}f_{fa}+\frac{1}{d_i}(\sum_{v}a_vf_i+\sum_{v}b_v)\\
d_if_i&=d_i+f_{fa}+\sum_{v}a_vf_i+\sum_{v}b_v\\
(d_i-\sum_{v}a_v)f_i&=d_i+f_{fa}+\sum_{v}b_v\\
f_i&=\frac{1}{d_i-\sum_{v}a_v}f_{fa}+\frac{\sum_{v}b_v+d_i}{d_i-\sum_{v}a_v}\\
\end{align}
\]

  这样就可以从下往上递推得到\(a_i,b_i\)。

  那么答案就是 \(b_x\)

  然后就可以轻松算出询问每一个集合的答案了。

  时间复杂度:\(O(n2^n\log p+qn)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c,b=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-')
{
c=getchar();
b=1;
}
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return b?-s:s;
}
void put(int x)
{
if(!x)
{
putchar('0');
return;
}
static int c[20];
int t=0;
while(x)
{
c[++t]=x%10;
x/=10;
}
while(t)
putchar(c[t--]+'0');
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
const ll p=998244353;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
ll f[100];
ll g[100];
vector<int> a[100];
int d[100];
int b[100];
void dfs(int x,int fa)
{
if(b[x])
{
f[x]=g[x]=0;
return;
}
f[x]=0;
g[x]=d[x];
ll k=d[x];
for(auto v:a[x])
if(v!=fa)
{
dfs(v,x);
k=(k-f[v])%p;
g[x]=(g[x]+g[v])%p;
}
k=fp(k,p-2);
f[x]=k;
g[x]=g[x]*k%p;
}
int n,q,rt;
ll s[1<<20];
int main()
{
open("loj2542");
scanf("%d%d%d",&n,&q,&rt);
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
d[x]++;
d[y]++;
}
for(int i=1;i<1<<n;i++)
{
int num=0;
for(int j=1;j<=n;j++)
{
b[j]=((i>>(j-1))&1);
num+=b[j];
}
dfs(rt,0);
s[i]=g[rt];
if(!(num&1))
s[i]=-s[i];
}
for(int i=1;i<=n;i++)
for(int j=0;j<1<<n;j++)
if((j>>(i-1))&1)
s[j]=(s[j]+s[j^(1<<(i-1))])%p;
int k;
for(int i=1;i<=q;i++)
{
scanf("%d",&k);
x=0;
for(int i=1;i<=k;i++)
{
scanf("%d",&y);
x|=1<<(y-1);
}
printf("%lld\n",(s[x]+p)%p);
}
return 0;
}

【LOJ2542】【PKUWC 2018】随机游走 min-max容斥 树上高斯消元的更多相关文章

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

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

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

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

  3. 【LOJ#2542】[PKUWC2018]随机游走(min-max容斥,动态规划)

    [LOJ#2542][PKUWC2018]随机游走(min-max容斥,动态规划) 题面 LOJ 题解 很明显,要求的东西可以很容易的进行\(min-max\)容斥,那么转为求集合的\(min\). ...

  4. 洛谷 P5643 - [PKUWC2018]随机游走(Min-Max 容斥+FWT+树上高斯消元,hot tea)

    题面传送门 一道挺综合的 hot tea,放到 PKUWC 的 D2T2 还挺喜闻乐见的( 首先我们考虑怎样对一个固定的集合 \(S\) 计算答案,注意到我们要求的是一个形如 \(E(\max(S)) ...

  5. [PKUWC 2018]随机游走

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

  6. 【洛谷5643】[PKUWC2018] 随机游走(Min-Max容斥+待定系数法+高维前缀和)

    点此看题面 大致题意: 从一个给定点出发,在一棵树上随机游走,对于相邻的每个点均有\(\frac 1{deg}\)的概率前往.多组询问,每次给出一个点集,求期望经过多少步能够访问过点集内所有点至少一次 ...

  7. BZOJ3141 Hnoi2013 游走 【概率DP】【高斯消元】*

    BZOJ3141 Hnoi2013 Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点 ...

  8. 【BZOJ3143】【HNOI2013】游走 && 【BZOJ3270】博物馆 【高斯消元+概率期望】

    刚学完 高斯消元,我们来做几道题吧! T1:[BZOJ3143][HNOI2013]游走 Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小 ...

  9. LOJ2542 PKUWC2018 随机游走 min-max容斥、树上高斯消元、高维前缀和、期望

    传送门 那么除了D1T3,PKUWC2018就更完了(斗地主这种全场0分的题怎么会做啊) 发现我们要求的是所有点中到达时间的最大值的期望,\(n\)又很小,考虑min-max容斥 那么我们要求从\(x ...

随机推荐

  1. Dynamics 365 POA表记录的查询

    微软动态CRM专家罗勇 ,回复313或者20190311可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . PrincipalO ...

  2. keras & tensorflow 列出可用GPU 和 切换CPU & GPU

    列出可用GPU from tensorflow.python.client import device_lib print(device_lib.list_local_devices()) from ...

  3. iOS----------The Apple Developer Program License Agreement has been updated.

    The Apple Developer Program License Agreement has been updated. In order to access certain membershi ...

  4. DVWA 黑客攻防演练(二)暴力破解 Brute Froce

    暴力破解,简称"爆破".不要以为没人会对一些小站爆破.实现上我以前用 wordpress 搭建一个博客开始就有人对我的站点进行爆破.这是装了 WordfenceWAF 插件后的统计 ...

  5. Rsync客户端卡死的问题查询

    简介 某备份系统大量使用rsync来传输文件,但是偶尔会出现rsync客户端在上传数据的时候长时间卡死,本文记录了解决问题的步骤. 本文只涉及rsync客户端中IO相关逻辑,关于rsync的发送算法并 ...

  6. GDB 显示别的文件;在别文件打断点;执行到函数末尾;跳出当前函数

    显示别的文件:l "文件名.后缀名":行号 在别文件打断点:b "文件名.后缀名":行号 执行到函数末尾:finish 跳出当前函数(当前位置到函数的末尾不被执 ...

  7. 【PAT】B1016 部分A+B

    水题 以字符和字符串形式储存输入,比较,计算出两个个数的D的个数,用for循环拼成P,相加得出结果 #include<stdio.h> int main(){ char A[20],DA, ...

  8. 安装指定版本的docker服务

    参考博客:Docker CE 镜像源站 参考博客:docker启动异常driver not supported 1. 说明 之前部署docker服务的时候都是安装最新的docker版本,并使用dock ...

  9. me

    PXKUNUIN6A- eyJsaWNlbnNlSWQiOiJQWEtVTlVJTjZBIiwibGljZW5zZWVOYW1lIjoi5b285bK4IDEiLCJhc3NpZ25l ZU5hbWU ...

  10. Hadoop Yarn配置项 yarn.nodemanager.resource.local-dirs探讨

    1. What is the recommended value for "yarn.nodemanager.resource.local-dirs"? We only have ...