$ Min$-$Max$容斥真好用

$ PKUWC$滚粗后这题一直在$ todolist$里

今天才补掉..还要更加努力啊..

LOJ #2542

题意:给一棵不超过$ 18$个节点的树,$ 5000$次询问,每次问从根随机游走走遍一个集合的期望步数


$ Solution:$

考虑$ Min$-$Max$容斥

有$ Max(S)=\sum\limits_{T \subseteq S}(-1)^{|T|+1}Min(T)$

其中$ S,T$是一个集合,$Max(S)$表示$ S$中最大元素,$Min(S)$同理

$ update$评论区已经给出证明

我们设集合$ S$表示走到每个点的期望时间

显然走遍一个集合的期望时间就是$ Max(S)$

且第一次走到某集合的期望时间是$ Min(S)$

$ Max(S)$不容易计算,我们转而求解$ Min(S)$

令$f_i$表示从点$ i$随机游走第一次走到集合$ S$的期望步数

这个显然可以高斯消元,不过复杂度略大

由于转移是在树上,可以直接在树上$ O(n)$消元

我们令$ f_i=k_if_{fa[i]}+b_i$

当$ i$在集合$ S$中的时候$k_i=b_i=0$否则进行转移

转移的时候把当前点孩子的$ k$和$ b$算出然后代到当前点的方程中算出当前点的$ k$和$ b$

这样可以在$O(2^n·n*算逆元复杂度)$的时间复杂度内算出所有的$ Min(S)$

然后直接容斥算$ Max(S)$,复杂度是$ 5000*2^n$的

我们可以提前预处理每个$ Max(S)$每次枚举子集转移,时间复杂度是$ 3^n$的

据说都能过

不过其实这部分可以优化到$ 2^n*n$的

我们直接根据$ popcount(S)$的奇偶性来判断是否给$ Min(S)$乘上$ -1$

然后直接高维前缀和即可


$ my \ code:$

  1. #include<ctime>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<iostream>
  6. #include<algorithm>
  7. #include<queue>
  8. #define p 998244353
  9. #define rt register int
  10. #define ll long long
  11. using namespace std;
  12. inline ll read(){
  13. ll x = ; char zf = ; char ch = getchar();
  14. while (ch != '-' && !isdigit(ch)) ch = getchar();
  15. if (ch == '-') zf = -, ch = getchar();
  16. while (isdigit(ch)) x = x * + ch - '', ch = getchar(); return x * zf;
  17. }
  18. void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
  19. void writeln(const ll y){write(y);putchar('\n');}
  20. int i,j,k,m,n,x,y,z,cnt,Root;
  21. struct ret{
  22. int k,b;//k*father + b
  23. ret operator +(const ret s)const{
  24. return {(k+s.k)%p,(b+s.b)%p};
  25. }
  26. ret operator *(const int s)const{
  27. return {1ll*k*s%p,1ll*b*s%p};
  28. }
  29. }f[][<<];
  30. int F[],L[],N[],a[],d[],inv[],Min[<<];
  31. void add(int x,int y){
  32. a[++k]=y;
  33. if(!F[x])F[x]=k;
  34. else N[L[x]]=k;
  35. L[x]=k;
  36. }
  37. int ksm(int x,int y){
  38. int ans=;
  39. for(rt i=y;i;i>>=,x=1ll*x*x%p)if(i&)ans=1ll*x*ans%p;;
  40. return (ans+p)%p;
  41. }
  42. ret dfs(int x,int pre,int s){
  43. if(s>>x-&)return{,};
  44. ret now={,};
  45. for(rt i=F[x];i;i=N[i])if(a[i]!=pre)now=now+dfs(a[i],x,s)*inv[d[x]];
  46. const int Inv=ksm(-now.k,p-);
  47. return {1ll*Inv*inv[d[x]]%p,1ll*Inv*(now.b+)%p};
  48. }
  49. #define cnt(x) __builtin_popcount(x)
  50. int main(){
  51. n=read();int Q=read();Root=read();
  52. inv[]=inv[]=;
  53. for(rt i=;i<=;i++)inv[i]=1ll*inv[p%i]*(p-p/i)%p;
  54. for(rt i=;i<n;i++){
  55. x=read();y=read();
  56. add(x,y);
  57. add(y,x);
  58. d[x]++;d[y]++;
  59. }
  60. for(rt i=;i<(<<n);i++){
  61. ret ans=dfs(Root,Root,i);
  62. Min[i]=ans.b*(cnt(i)&?:-);
  63. }
  64. for(rt i=;i<n;i++)
  65. for(rt j=;j<<<n;j++)if(j>>i&)(Min[j]+=Min[j^(<<i)])%=p;
  66. while(Q--){
  67. x=read();int sum=;
  68. for(rt i=;i<=x;i++)
  69. sum|=(<<read()-);
  70. writeln((Min[sum]+p)%p);
  71. }
  72. return ;
  73. }

LOJ #2542「PKUWC2018」随机游走的更多相关文章

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

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

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

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

  3. LOJ 2542 「PKUWC2018」随机游走 ——树上高斯消元(期望DP)+最值反演+fmt

    题目:https://loj.ac/problem/2542 可以最值反演.注意 min 不是独立地算从根走到每个点的最小值,在点集里取 min ,而是整体来看,“从根开始走到点集中的任意一个点就停下 ...

  4. loj#2542. 「PKUWC2018」随机游走(MinMax容斥 期望dp)

    题意 题目链接 Sol 考虑直接对询问的集合做MinMax容斥 设\(f[i][sta]\)表示从\(i\)到集合\(sta\)中任意一点的最小期望步数 按照树上高斯消元的套路,我们可以把转移写成\( ...

  5. 【LOJ】#2542. 「PKUWC2018」随机游走

    题解 虽然我知道minmax容斥,但是--神仙能想到把这个dp转化成一个一次函数啊= = 我们相当于求给定的\(S\)集合里最后一个被访问到的点的时间,对于这样的max的问题,我们可以用容斥把它转化成 ...

  6. LOJ2542. 「PKUWC2018」随机游走

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

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

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

  8. 「PKUWC2018」随机游走

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

  9. loj2542「PKUWC2018」随机游走

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

随机推荐

  1. 利用twilio进行手机短信验证

    首先要注册 twilio 账号但是由于twilio人机验证用的是Goole所有注册需要FQ 完成后去免费获取15元使用 然后 pip install twilio 注册完成后会在个人首页显示你的免费金 ...

  2. python与java的猜拳游戏

    python版: import randomprint("-----猜拳游戏-----")print("---0.剪刀--1.石头--2.布---")while ...

  3. R语音:解决cor.test报错的 'y'必需是数值矢量

    'y'必需是数值矢量,产生该类报错可能是含有NA值. 只需要在该数值上加入as.double函数即可.见下命令: ##先测试是不是数值型 is.numeric(data[,2]) #[1] FALSE ...

  4. Day4--Python--列表增删改查,元组,range

    # 一.列表# 能装东西的东西 列表中装的数据是没有限制的,大小基本上够用# 列表用[]表示# 有索引和切片 [start,end,step] ###增删改查 (重点) # 1.新增 # appent ...

  5. DK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME

    根据提示,我们可以新建一个项目或者以前自己使用过没问题的工程,从中把local.properties文件copy到我们从github中想要导入的工程中,我自己就是这样的,然后这个问题就解决了. ndk ...

  6. JDBC动态查询MySQL中的表(按条件筛选)

    动态查询实现按条件筛选.PreparedStatement 准备语句指定要查询的表头列,.setString()通过赋值指定行,.executeQuery()执行语句 在数据库test里先创建表sch ...

  7. IIS 错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”

    导致这种问题的原因是ASP.NET没有成功注册到IIS中,很有可能是先安装.Net Framework,然后安装IIS.为了避免此问题发生,要先安装IIS再安装.Net Framework. 解决方案 ...

  8. qml: 另类图像轮播;

    一般来说,图像轮播都是采用ListView等model进行设计, 比较方便.  这里展示我自己设计的图像轮播 方案, 仅采用两个QImage实现: 下面展示代码以及简述:(注:  以下代码为本人原创, ...

  9. Linux 普通用户免密码切换到root用户

    Linux 普通用户免密码切换到root用户 # 添加用户 useradd user_name # 修改密码 echo "user_name@pwd" | passwd --std ...

  10. JDBC工具类

    package com.shundong.uitl; import java.sql.Connection; import java.sql.DriverManager; import java.sq ...