版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/87923436
Description
刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行或(c++,c的|,pascal
的or)操作。选择数字i的概率是p[i]。保证0<=p[i]<=1,Σp[i]=1问期望多少秒后,你手上的数字变成2^n-1。
Solution
考虑min-max容斥,我们枚举一次就选中的位记为T,问题在于求E(T)
不妨记
,显然
考虑补集转化,记
那么
这里求
也就是子集和,实际上直接做一次FWT就可以了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N=1049576;
double p[N];
int c[N];
void FWT(double *a,int n) {
for (int i=1;i<n;i<<=1) {
for (int j=0;j<n;j+=(i<<1)) {
for (int k=0;k<i;++k) {
a[j+k+i]+=a[j+k];
}
}
}
}
int main(void) {
freopen("data.in","r",stdin);
int n; scanf("%d",&n);
int lim=1<<n;
for (int i=0;i<lim;++i) {
scanf("%lf",&p[i]);
c[i]=c[i>>1]^(i&1);
}
FWT(p,lim);
double ans=0;
for (int i=1;i<lim;++i) {
if ((1-p[(lim-1)^i])>1e-8) {
ans+=(c[i]?(1.0):(-1.0))/(1-p[(lim-1)^i]);
}
}
if (ans<1e-8) puts("INF");
else printf("%.10lf\n", ans);
return 0;
}