Description

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

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

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

答案对 $998244353 $ 取模。

Solution

考虑 min-max 容斥,问题变成求从 \(x\) 点出发第一次到集合 \(S\) 中的点的期望步数

枚举集合 \(S\),尝试树形DP求出

设 \(f(i,S)\) 表示从点 \(i\) 出发第一次到达集合 \(S\) 中的点的期望步数

则有转移 \(f(i,S)=1+\frac1{deg(i)}\cdot f(fa[i],S)+\frac1{deg(i)}\sum\limits_{son}f(son,S)\)

根据我从没见过的树形DP常见套路,\(f(i)\) 一般都可以写成 \(A\cdot f(fa)+B\) 的形式

然后推式子

\[f(i,S)=1+\frac1{deg(i)}\cdot f(fa[i],S)+\frac1{deg(i)}(\sum\limits_{son}A(son)\cdot f(x)+B(son))
\]

\[f(i,S)=\frac1{deg(i)-\sum\limits_{son}A(son)}\cdot f(fa[i],S)+\frac{deg(i)+\sum\limits_{son}B(son)}{deg(x)-\sum\limits_{son}A(son)}
\]

得:\(A(i)=\frac1{deg(i)-\sum\limits_{son}A(son)},B(i)=\frac{deg(i)+\sum\limits_{son}B(son)}{deg(x)-\sum\limits_{son}A(son)}\)

当DP到一个 \(S\) 集合中的节点 \(p\) 时,令 \(A(p)=B(p)=0\),表示从这个点出发期望走 \(0\) 步就可以到达集合 \(S\) 中的点。最后的 \(B(x)\) 就是答案(因为 \(f(fa[x])\) 始终为 \(0\) )

Code

#include<bits/stdc++.h>
using std::min;
using std::max;
using std::swap;
using std::vector;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define all(A) A.begin(),A.end()
#define mp(A,B) std::make_pair(A,B)
#define int long long
const int N=19;
const int mod=998244353; int a[N],b[N],f[1<<N],cnts[1<<N];
int n,q,s,cnt,maxn,head[N],deg[N]; struct Edge{
int to,nxt;
}edge[N<<1]; void add(int x,int y){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
} int ksm(int a,int b=mod-2,int ans=1){
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;b>>=1;
} return ans;
} void dfs(int now,int fa,int S){
if(S>>now-1&1) return a[now]=b[now]=0,void();
for(int i=head[now];i;i=edge[i].nxt){
int to=edge[i].to;
if(to==fa) continue;
dfs(to,now,S);
(a[now]+=a[to])%=mod;(b[now]+=b[to])%=mod;
} a[now]=ksm((deg[now]-a[now]+mod)%mod);b[now]=(b[now]+deg[now])%mod*a[now]%mod;
} int getint(){
int X=0,w=0;char ch=getchar();
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while( isdigit(ch))X=X*10+ch-48,ch=getchar();
if(w) return -X;return X;
} signed main(){
n=getint(),q=getint(),s=getint();maxn=1<<n;
for(int i=1;i<n;i++){
int x=getint(),y=getint();
add(x,y),add(y,x);deg[x]++;deg[y]++;
}
for(int i=1;i<maxn;i++){
cnts[i]=cnts[i>>1]+(i&1);
memset(a,0,sizeof a),memset(b,0,sizeof b);
dfs(s,0,i);
f[i]=(cnts[i]&1?b[s]:mod-b[s]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<maxn;j++)
if(j>>i-1&1) (f[j]+=f[j^(1<<i-1)])%=mod;
while(q--){
int len=getint(),x=0;
while(len--) x|=1<<getint();
printf("%lld\n",f[x>>1]);
} return 0;
}

[PKUWC2018] 随机游走的更多相关文章

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

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

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

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

  3. [LOJ#2542] [PKUWC2018] 随机游走

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

  4. LOJ #2542 [PKUWC2018]随机游走 (概率期望、组合数学、子集和变换、Min-Max容斥)

    很好很有趣很神仙的题! 题目链接: https://loj.ac/problem/2542 题意: 请自行阅读 题解首先我们显然要求的是几个随机变量的最大值的期望(不是期望的最大值),然后这玩意很难求 ...

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

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

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

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

  7. 题解-PKUWC2018 随机游走

    Problem loj2542 题意:一棵 \(n\) 个结点的树,从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去,询问走完一个集合 \(S\)的期望时间,多组询问 \(n\le ...

  8. LOJ2542 PKUWC2018随机游走(概率期望+容斥原理)

    如果直接dp,状态里肯定要带上已走过的点的集合,感觉上不太好做. 考虑一种对期望的minmax容斥:其中Max(S)为遍历完S集合的期望步数,Min(S)为遍历到S集合中一个点的期望步数.当然才不管怎 ...

  9. [LOJ2542][PKUWC2018]随机游走(MinMax容斥+树形DP)

    MinMax容斥将问题转化为求x到S中任意点的最小时间. 树形DP,直接求概率比较困难,考虑只求系数.最后由于x节点作为树根无父亲,所以求出的第二个系数就是答案. https://blog.csdn. ...

随机推荐

  1. Fiddler-设置取消自动更新

    fiddler 启动时老弹出要更新,但不想更新,可以这样设置 Tools-Optons->General 把第一个√去掉

  2. 缓存为王-varnish

    2.varnish的软件清单 [root@centos69 ~]# rpm -ql varnish /etc/logrotate.d/varnish /etc/rc.d/init.d/varnish ...

  3. [转]Java工程师技术栈--成神之路

    一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133http://if ...

  4. Linux目录/usr结构说明

    在 linux 文件结构中,有一个很神奇的目录 -- /usr. 讨论中,大部分观点认为: usr 是 unix system resources 的缩写: usr 是 user 的缩写: usr 是 ...

  5. Vim常用的命令

    Noted:均在命令模式下进行的 移动: j---->向下 k---->向上 l---->向右 h---->向左 保存: w---->保存 退出: q---->退出 ...

  6. WebPackBrows

    一个http工具,通过java编写 调用方法 s.y.webpackbrows.fac.WebPackFactor.getConnection 还会继续完善 下载位置 https://pan.baid ...

  7. Python之路【第五篇】函数

    4.1 函数的定义 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 4.2 函数的创建 函数名的命名规则: 1.函数名必须以下划线或字母开头,可以包含任 ...

  8. Python小练习之判断一个日期是一年的第几天

    python练手遇到的一个问题写了个统一公式,不用麻烦的分各种类,如果有人测试出错误请评论通知. #分单双月 def dayNum(month,day,isLeap): if month % 2 != ...

  9. Chapter 1: Plug-in programing from past to the future

    It is the best time. Although the internal API of Android not allowed to be modified by google play, ...

  10. Dubbo 源码分析 - 集群容错之 LoadBalance

    1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...