[luogu 3175] [HAOI2015]按位或(min-max容斥+高维前缀和)

[luogu 3175] [HAOI2015]按位或

题面

刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2n-1]的数字,与你手上的数字进行按位或运算。问期望多少秒后,你手上的数字变成2n-1。

分析

前置知识:min-max容斥

\(\max(S)\)为集合\(S\)中的最大值,\(\min(S)\)为集合\(S\)中的最小值(如果\(S=\emptyset\)

,那\(\max(S)=\min(S)=0\)),那么有

\[\max(S)=\sum _{T\subseteq S}\left( -1\right) ^{|T|-1} \min(T) \]

这里感性理解一下就好了

前置知识:高维前缀和

戳这里


把二进制数看成一个集合,第i位为1表示集合里有元素i.设全集\(U\)为二进制数\(2^n-1\)对应的集合

\(\max(S)\)为S中最后一个元素被或为1的期望时间,min就是最先被或为1的元素的期望时间,那么答案就是\(\max(U)\)

根据min-max容斥,我们有

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

因为是最先被或为1,根据定义我们有

\[\min(T)=\frac{1}{\sum_{X \subseteq U , X \cap T \neq \emptyset }p(x)} \]

那么

\[\begin{aligned} \min(T) &= \frac{1}{\sum_{X \subseteq U , X \cap T \neq \emptyset }p(x)} \\ &=\frac{1}{1-\sum_{X \subseteq U,X \cap T = \emptyset} p(x)} \\&= \frac{1}{1-\sum_{X \subseteq U-T} p(x)}\end{aligned} \]

其实就是用了2次补集转化,然后\(\sum_{X \subseteq U-T} p(x)\)显然就是一个高维前缀和,直接套模板就可以了

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 20
#define eps 1e-10
using namespace std;
int n;
double p[(1<<maxn)+5];

int count_1(int x){
	int ans=0;
	while(x){
		if(x&1) ans++;
		x>>=1; 
	}
	return ans;
}

int main(){
	scanf("%d",&n);
	for(int i=0;i<(1<<n);i++) scanf("%lf",&p[i]);
	for(int i=0;i<n;i++){
		for(int j=0;j<(1<<n);j++){
			if(j&(1<<i)) p[j]+=p[j^(1<<i)];
		}
	}
	double ans=0;
	int all=(1<<n)-1;
	for(int i=1;i<=all;i++){
		if(fabs(1-p[all^i])<eps) continue;//防止除0错误
		ans+=pow(-1,count_1(i)-1)*1/(1-p[all^i]);
	}
	if(fabs(ans)<eps) printf("INF");
	else printf("%.10lf",ans);
}
 
posted @ 2019-11-12 17:07  birchtree  阅读(220)  评论(0编辑  收藏  举报