码迷,mamicode.com
首页 > 其他好文 > 详细

按位或「HAOI2015」

时间:2019-11-12 17:25:55      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:思路   pre   有一个   ++   putchar   main   rac   bit   https   

题意

刚开始你有一个数字\(0\),每一秒钟你会随机选择一个\([0,2^n-1]\)的数字,与你手上的数字进行或(c++,c的|,pascal的or)操作。选择数字\(i\)的概率是\(p[i]\)。保证\(0<=p[i]<=1\)\(Σp[i]=1\)问期望多少秒后,你手上的数字变成\(2^n-1\)

思路

minmax容斥加上高维前缀和。

minmax容斥就是两个式子:

\[E(MAX(S))=\sum_{T\subseteq S}(-1)^{|T|-1}E(MIN(T))\]
\[E(MIN(S))=\sum_{T\subseteq S}(-1)^{|T|-1}E(MAX(T))\]

简单来说就是奇加偶减。其中\(E(MAX(S))\)表示\(S\)中最大的元素的期望,反之亦然。

这个东西的证明需要使用二项式反演,但我并不会,所以只好先背结论。如果要看证明可以去这里

对于本题,如果我们把所有位被填上的期望时间放到一个集合里,那么求的答案就是这个集合的最大值,发现符合我们式子的左半边。

那么式子右边就是至少有一个数字出现的期望时间。这里需要用到一个结论:\(MIN(T)\)的期望为其概率的倒数。(这个证明不是很复杂,这里不放了)

那么有\(E(MIN(T))=\frac{1}{\sum_{s'\cap T\neq 0}~~P_{s'}}\)(公式好像有点抽搐)

但是求相交不是很容易,所以我们转换为求不相交,这个比较简单,也就是

\[E(MIN(T))=\frac{1}{1-\sum_{s'与T没有相交}~~~~~P_{s'}}\]

分母后面那个东西可以表示为\[\sum_{s'\subseteq (2^n-1-T)}P_{s'}\]

而这个东西可以高维前缀和搞,于是这道题就结束了。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO{

    template<typename T>inline void read(T &x){
        x=0;T f=1;char c=getchar();
        for(; c<'0'||c>'9'; c=getchar()) if(c=='-') f=-1;
        for(; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
        x*=f;
    }

    template<typename T>inline void write(T x){
        if(x<0) putchar('-'),x*=-1;
        if(x>=10) write(x/10);
        putchar(x%10+'0');
    }

} using namespace StandardIO;

namespace Project{
    
    const int N=1<<21;
    
    int n,tot;
    double p[N];
    int num[N];
    double ans;

    inline void MAIN(){
        read(n);
        for(register int i=0; i<(1<<n); ++i){
            scanf("%lf",&p[i]);
            if(p[i]) tot|=i;
        }
        if(tot!=(1<<n)-1) return puts("INF"),void();
        for(register int i=1; i<(1<<n); ++i) num[i]=num[i>>1]+(i&1);
        for(register int i=0; i<n; ++i){
            for(register int j=0; j<(1<<n); ++j){
                if(j&(1<<i)) p[j]+=p[j^(1<<i)];
            }
        }
        for(register int i=1; i<(1<<n); ++i){
            ans+=(num[i]&1?1.0:-1.0)/(1.0-p[((1<<n)-1)^i]);
        }
        printf("%.6lf",ans);
    }

}

int main(){
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    Project::MAIN();
}

按位或「HAOI2015」

标签:思路   pre   有一个   ++   putchar   main   rac   bit   https   

原文地址:https://www.cnblogs.com/ilverene/p/11843381.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!