Description
刚开始你有一个数字0,每一秒钟你会随机选择一个 [ 0 , 2 n − 1 ] [0,2^n-1] [0,2n−1]的数字,与你手上的数字进行或(c++,c的|,pascal的or)操作。选择数字i的概率是p[i]。保证0<=p[i]<=1,Σp[i]=1问期望多少秒后,你手上的数字变成2^n-1。
Solution
考虑min-max容斥,问题转化为算出每个子集第一个出现元素的期望时间。对于一个子集 S S S,直接算所有与它有交的子集概率和不好算,补集转化一下,算与它没有交集的子集概率和,就是它的补集的所有子集。FWT就行了。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int inf=2147483647;
const double eps=1e-9;
int n,one[1<<20];double a[1<<20],ans=0,s[20];
int main()
{
scanf("%d",&n);
for(int i=0;i<(1<<n);i++)scanf("%lf",&a[i]);
one[0]=0;for(int S=1;S<(1<<n);S++)one[S]=one[S>>1]+(S&1);
for(int S=1;S<(1<<n);S++)
for(int i=0;i<n;i++)
if(S&(1<<i))s[i]+=a[S];
for(int i=0;i<n;i++)if(s[i]<eps)return puts("INF"),0;
for(int i=0;i<n;i++)
for(int S=0;S<(1<<n);S++)
if(S&(1<<i))a[S]+=a[S^(1<<i)];
for(int S=1;S<(1<<n);S++)
if(one[S]&1)
{
double t=1.0-a[((1<<n)-1)^S];
if(t>eps)ans+=1.0/t;
}
else
{
double t=1.0-a[((1<<n)-1)^S];
if(t>eps)ans-=1.0/(1.0-a[((1<<n)-1)^S]);
}
printf("%.10lf",ans);
}