把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ4036】[HAOI2015] 按位或(Min-Max容斥+FWT)

点此看题面

大致题意: 每个单位时间有\(p_i\)的概率选中\(i∈[0,2^n-1]\),求期望多少时间后选中的数按位或的结果变成了\(2^n-1\)

前言

典型的数学题:看起来很吓人的知识点+似乎很高深的分析+短短几行的代码。。。

分析

要做这道题,首先我们要知道一个叫做\(Min-Max\)容斥的东西:

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

具体地,在这题中,\(E(min(T))\)表示\(T\)中出现任意一位的期望时间,\(E(max(S))\)表示\(S\)中所有位都出现的期望时间(这里的\(S\)即为\(2^n-1\))。

换言之,我们只要能求出\(E(min(T))\),就可以在\(O(2^n)\)的时间复杂度内通过容斥求出\(E(max(S))\)。那么我们只需要考虑如何求一个集合中出现任意一位的期望时间。

首先自然有一个很暴力的式子:

\[E(min(T))=\frac1{\sum_{i∩T\not=\varnothing}p_i} \]

这个式子的关键是分母中的概率,且这个东西显然不好维护。因此我们反过来考虑:出现任意一位的概率就是\(1-\)不出现任意一位的概率。

也即是说:

\[E(min(T))=\frac1{1-\sum_{i∩T=\varnothing}p_i} \]

\(k=T\ xor\ (2^n-1)\)(即\(T\)的补集),那么这个式子就相当于是:

\[E(min(T))=\frac1{1-\sum_{i\subseteq k}p_i} \]

显然\(\sum_{i\subseteq k}p_i\)可以用\(FWT\)高效地求出,于是这题就做完了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 20
#define DB double
using namespace std;
int n,s,op[1<<N];DB p[1<<N];
int main()
{
	RI i,g=0;for(scanf("%d",&n),s=1<<n,i=0;i^s;++i) scanf("%lf",p+i);//读入
	for(i=0;i^s;++i) p[i]&&(g|=i);if(g^(s-1)) return puts("INF"),0;//判无解
	RI j,k;for(i=1;i^s;i<<=1) for(j=0;j^s;j+=i<<1) for(k=0;k^i;++k) p[i+j+k]+=p[j+k];//FWT
	DB t=0;for(op[0]=-1,i=0;i^s;++i)//Min-Max容斥
		op[i]=op[i>>1]*(i&1?-1:1),p[i^(s-1)]<1-1e-8&&(t+=op[i]/(1-p[i^(s-1)]));
	return printf("%.10lf\n",t),0;
}
posted @ 2020-06-04 09:47  TheLostWeak  阅读(119)  评论(0编辑  收藏  举报