题面
刚开始你有一个数字 \(0\),每一秒钟你会随机选择一个 \([0,2^n-1]\) 的数字,与你手上的数字进行或(C++, C 的 |
, Pascal 的 or
)操作。选择数字 \(i\) 的概率是 \(p[i]\)(保证 \(0 \leq p[i] \leq 1, \ \sum p[i] = 1\)) 问期望多少秒后,你手上的数字变成 \(2^n-1\)。\(n \leq 20\) 。
Solution
$ \text{min-max}$ 容斥。
答案即求 \(E(\max(S))\) 即全集 \(S\) 最后一个元素出现时间的期望。
根据 $ \text{min-max}$ 容斥 :
\[ E(\max(S))=\sum_{T\subseteq S} ( -1)^{T+1} E(\min(T)) \]
(注:下文中 \(S,T\) 并非上文中的 \(S,T\) )
考虑求 \(E(\min(S))\) 即集合 \(S\) 第一个元素出现时间的期望。
\[ E(\min(S)) = \frac{1}{\sum_{T\cap S \neq \emptyset}P_T} \]
考虑补集转化,设 \(S'\) 为 \(S\) 的补集。
\[ E(\min(S)) = \frac{1}{1-\sum_{T\subseteq S'}P_T} \]
直接高维前缀和即可。
code
#include<cstdio>
#include<cmath>
const int N=(1<<20)+5;
double p[N],ans;
int main()
{
int n; scanf("%d",&n);
for(int i=0;i<(1<<n);++i)
{
scanf("%lf",&p[i]);
if(fabs(p[i])<1e-7)
{
puts("INF");
return 0;
}
}
for(int i=0;i<n;++i)
for(int j=0;j<(1<<n);++j)
if(j&(1<<i)) p[j]+=p[j^(1<<i)];
for(int i=1;i<(1<<n);++i)
{
int s=0;
for(int j=0;j<n;++j) s+=!!(i&(1<<j));
double tmp=1.0/(1.0-p[i^((1<<n)-1)]);
(s-1)&1?ans-=tmp:ans+=tmp;
}
printf("%.7lf",ans);
}