【HAOI 2015】按位或

传送门


Problem

刚开始你有一个数字 0 0 0,每一秒钟你会随机选择一个 [ 0 , 2 n − 1 ] [0,2^n-1] [0,2n1] 的数字,与你手上的数字进行或操作。选择数字 i i i 的概率是 p i p_i pi,保证 0 ≤ p i ≤ 1 0\le p_i\le1 0pi1 ∑ p i = 1 \sum p_i=1 pi=1。问期望多少秒后,你手上的数字变成 2 n − 1 2^n-1 2n1

数据范围: n ≤ 20 n\le20 n20


Solution

m a x ( S ) max(S) max(S) S S S 中每一位都是 1 1 1 的期望时间, m i n ( S ) min(S) min(S) S S S 中至少有一个 1 1 1 的期望时间。

那么 m i n ( S ) min(S) min(S) 很好算:

m i n ( S ) = 1 ∑ T ∩ S = ̸ ∅ p T min(S)=\frac 1{\sum_{T\cap S=\not \varnothing}p_T} min(S)=TS≠pT1

这里的 S S S T T T 其实可以看作是一个数。

继续化简:

m i n ( S ) = 1 1 − ∑ T ∩ S = ∅ p T \begin{aligned} min(S)&=\frac{1}{1-\sum_{T\cap S=\varnothing}p_T} \end{aligned} min(S)=1TS=pT1

U U U 表示全集,即 U = 2 n − 1 U=2^n-1 U=2n1,那么有:

m i n ( S ) = 1 1 − ∑ T ∩ ∁ U S = T p T min(S)=\frac{1}{1-\sum_{T\cap ∁_U^S=T}p_T} min(S)=1TUS=TpT1

T ∩ ∁ U S = T T\cap ∁_U^S=T TUS=T 的意思是 T T T ∁ U S ∁_U^S US 的子集,所以我们需要统计的就是 ∁ U S ∁_U^S US 子集的概率和,这个用 FWT 即可。

然后计算出 m i n ( S ) min(S) min(S) 后,就可以用 min-max 容斥算出 m a x ( S ) max(S) max(S) 了。

时间复杂度 O ( n 2 n ) O(n2^n) O(n2n)


Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000005
#define eps 1e-8
using namespace std;
int n,now=0;
double ans,p[N];
void FWT(double *f){
	for(int i=0;i<n;++i)
		for(int j=0;j<(1<<n);++j)
			if(j&(1<<i))  f[j]+=f[j^(1<<i)];
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<(1<<n);++i){
		scanf("%lf",&p[i]);
		if(p[i]>eps)  now|=i;
	}
	if(now^((1<<n)-1))  return puts("INF"),0;
	FWT(p);
	for(int i=1;i<(1<<n);++i){
		int tot=0,x=i^((1<<n)-1);
		for(int j=1;j<=n;++j)  if(i&(1<<(j-1)))  tot++;
		ans+=((tot&1)?1.0:-1.0)/(1.0-p[x]);
	}
	printf("%.10lf\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值