【LOJ2127】「HAOI2015」按位或

题面

刚开始你有一个数字 \(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);
}

猜你喜欢

转载自www.cnblogs.com/farway17/p/11002009.html