【HAOI2015】【容斥】【FMT】按位或

【描述】
刚开始你有一个数字 0,每一秒钟你会随机选择一个 [ 0 , 2 n − 1 ] [0,2^n −1] [0,2n1]的数字,与你手上的数字进行或(C++, C 的 |, Pascal 的 or)操作。选择数字 i 的概率是 p[i](保证 0 ≤ p [ i ] ≤ 1 , ∑ p [ i ] = 1 0≤p[i]≤1, ∑p[i]=1 0p[i]1,p[i]=1) 问期望多少秒后,你手上的数字变成 2 n − 1 2^n-1 2n1
【输入】
第一行输入 n 表示 n 个元素,第二行输入 2 n 2^n 2n个数,第 i 个数表示选到 i−1的概率。
【输出】
仅输出一个数表示答案,绝对误差或相对误差不超过 1 0 − 6 10^{-6} 106 即可算通过。如果无解则要输出INF

【思路】

首先,我们要求的就是最晚出现的一个1出现的时间的期望。考虑minmax容斥,我们要求全集的每个子集S最早的一个1出现的期望,容斥系数为 ( − 1 ) ∣ S ∣ − 1 (-1)^{|S|-1} (1)S1。即我们选出的数的与S有交集的期望时间,记这个概率为P,那么期望为 1 P \frac{1}{P} P1。而这个概率加上每个与S没有交集的数出现的概率之和就是1,所以我们计算出每个与S没有交集的数出现的概率之和。这是一个子集求和,FMT即可。
代码:

#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=2e6+5;
int U=0,siz[N],n,m,a,b,c;
inline void FMT(double *f)
{
	for(int re i=0;i^n;i++)
		for(int re j=0;j^U;j++)
			if(j&(1<<i))f[j]+=f[j^(1<<i)];
}
double ans=0,f[N];
int s[2]={-1,1};
int main()
{
	scanf("%d",&n);U=(1<<n);
	for(int re i=0;i^U;i++)scanf("%lf",&f[i]);
	for(int re i=0;i^U;i++)
		for(int re j=0;j^n;j++)
			if(i&(1<<j))++siz[i];
	FMT(f);
	for(int re i=1;i^U;i++)
	{
		if(1.0-f[i^(U-1)]<1e-10)return puts("INF"),0;
		f[i^(U-1)]=1.0/(1.0-f[i^(U-1)]);
		ans+=s[siz[i]&1]*f[i^(U-1)];
	}
	printf("%.6f",ans);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值