【LOJ2542】【PKUWC 2018】随机游走 min-max容斥 树上高斯消元
题目描述
有一棵 \(n\) 个点的树。你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去。
有 \(q\) 次询问,每次询问给定一个集合 \(S\),求如果从 \(x\) 出发一直随机游走,直到点集 \(S\) 中所有点都至少经过一次的话,期望游走几步。
特别地,点 \(x\)(即起点)视为一开始就被经过了一次。
答案对 \(998244353\) 取模。
题解
这道题要求点集 \(S\) 中所有点都至少经过一次的期望步数,直接做不好做,要先用一个 min-max 容斥转换成走到点集 \(S\) 中第一个点的期望步数:
\]
然后就可以列方程高斯消元了。
\(f_i\) 表示从 \(i\)走到最近的点所需要的最小步数。
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\)。
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容斥 树上高斯消元的更多相关文章
- loj2542 「PKUWC2018」随机游走 MinMax 容斥+树上高斯消元+状压 DP
题目传送门 https://loj.ac/problem/2542 题解 肯定一眼 MinMax 容斥吧. 然后问题就转化为,给定一个集合 \(S\),问期望情况下多少步可以走到 \(S\) 中的点. ...
- 「PKUWC2018」随机游走(min-max容斥+FWT)
「PKUWC2018」随机游走(min-max容斥+FWT) 以后题目都换成这种「」形式啦,我觉得好看. 做过重返现世的应该看到就想到 \(min-max\) 容斥了吧. 没错,我是先学扩展形式再学特 ...
- 【LOJ#2542】[PKUWC2018]随机游走(min-max容斥,动态规划)
[LOJ#2542][PKUWC2018]随机游走(min-max容斥,动态规划) 题面 LOJ 题解 很明显,要求的东西可以很容易的进行\(min-max\)容斥,那么转为求集合的\(min\). ...
- 洛谷 P5643 - [PKUWC2018]随机游走(Min-Max 容斥+FWT+树上高斯消元,hot tea)
题面传送门 一道挺综合的 hot tea,放到 PKUWC 的 D2T2 还挺喜闻乐见的( 首先我们考虑怎样对一个固定的集合 \(S\) 计算答案,注意到我们要求的是一个形如 \(E(\max(S)) ...
- [PKUWC 2018]随机游走
Description 题库链接 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次询问给定一个集合 \(S\) ...
- 【洛谷5643】[PKUWC2018] 随机游走(Min-Max容斥+待定系数法+高维前缀和)
点此看题面 大致题意: 从一个给定点出发,在一棵树上随机游走,对于相邻的每个点均有\(\frac 1{deg}\)的概率前往.多组询问,每次给出一个点集,求期望经过多少步能够访问过点集内所有点至少一次 ...
- BZOJ3141 Hnoi2013 游走 【概率DP】【高斯消元】*
BZOJ3141 Hnoi2013 Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点 ...
- 【BZOJ3143】【HNOI2013】游走 && 【BZOJ3270】博物馆 【高斯消元+概率期望】
刚学完 高斯消元,我们来做几道题吧! T1:[BZOJ3143][HNOI2013]游走 Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小 ...
- LOJ2542 PKUWC2018 随机游走 min-max容斥、树上高斯消元、高维前缀和、期望
传送门 那么除了D1T3,PKUWC2018就更完了(斗地主这种全场0分的题怎么会做啊) 发现我们要求的是所有点中到达时间的最大值的期望,\(n\)又很小,考虑min-max容斥 那么我们要求从\(x ...
随机推荐
- 谷歌AI涉足艺术、太空、外科手术,再强调AI七原则
谷歌AI涉足艺术.太空.外科手术,再强调AI七原则 https://mp.weixin.qq.com/s/MJG_SvKCEBKRvL3IWpL0bA 9月18日上午,Google在上海的2018世界 ...
- Azure WebJob-Custom Schedule for Azure Web Job Timer Triggers
如果想实现Azure Schedule WebJob,有两种方法: 1. 配置CRON Expression,网上有在线CRON配置工具,根据业务需要配置即可 注意:Azure的CRON Expres ...
- ubuntu下解压rar文件
ubuntu 下rar解压工具安装方法: 压缩功能 sudo apt-get install rar 1 解压功能 sudo apt-get install unrar 1 使用 可以直接在UI界面使 ...
- C语言----int (*p)[4] ---思考总结
a+1 跳4个int (*a)+1 跳一个int
- 【技术文章】《快速上手nodejs》
本文地址:http://www.cnblogs.com/aiweixiao/p/8294814.html 原文地址: 扫码关注微信公众号 1.写在前面 nodejs快速上手 nodejs使ja ...
- Windows Service 学习系列(三)——循环引擎 ICycleEngine
摘要:转载:https://www.cnblogs.com/zhuweisky/archive/2009/09/01/1557792.html#undefined 1.缘起: 有些系统需要每隔一段时间 ...
- git添加/删除远程仓库
注意:仓库只有管理员建的你才有权限上传,不然自己建的也没用,没权限上传 1.远程仓库路径查询 git remote -v 2.添加远程仓库 git remote add origin <你的项目 ...
- android开发学习 ------- 关于getSupportFragmentManager()不可用的问题
在Android开发中,少不了Fragment的运用. 目前在实际运用中,有v-4包下支持的Fragment以及app包下的Fragment,这两个包下的FragmentManager获取方式有点区别 ...
- 正益工作能担起PaaS+SaaS的未来探索吗?
没有竞争,行业没有未来.不参与竞争,企业没有未来.中国企业的类型纷繁复杂,也决定了企业的多样化需求.云计算和移动化的双重叠加,企业管理需要重新梳理,企业业务创新日益频繁,个性化需求日益突出,软件服务商 ...
- python3 Counter模块
from collections import Counter c = Counter("周周周周都方法及")print(c)print(type(c))print('__iter ...