Problem
刚开始你有一个数字 0 0 0,每一秒钟你会随机选择一个 [ 0 , 2 n − 1 ] [0,2^n-1] [0,2n−1] 的数字,与你手上的数字进行或操作。选择数字 i i i 的概率是 p i p_i pi,保证 0 ≤ p i ≤ 1 0\le p_i\le1 0≤pi≤1, ∑ p i = 1 \sum p_i=1 ∑pi=1。问期望多少秒后,你手上的数字变成 2 n − 1 2^n-1 2n−1。
数据范围: n ≤ 20 n\le20 n≤20。
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)=∑T∩S≠∅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)=1−∑T∩S=∅pT1
设 U U U 表示全集,即 U = 2 n − 1 U=2^n-1 U=2n−1,那么有:
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)=1−∑T∩∁US=TpT1
而 T ∩ ∁ U S = T T\cap ∁_U^S=T T∩∁US=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;
}