LOJ #2127. 「HAOI2015」按位或 min-max容斥+FWT

题意:
给定 $1$ ~ $2^n-1$ 每个数出现的概率.       

每次会随机选择一个数字,与手中的数字 or 起来.    

求:期望多少次使得手中的数字等于 $2^n-1$.    

题解:    

考虑 min-max 容斥.    

$\max(S)=\sum_{T \subseteq S} (-1)^{|T|} \min(T)$.    

套一个期望这个式子也是成立的:$E( \max (S))=\sum_{T \subseteq S} (-1)^{|T|} E( \min(T))$.    

$E(\min(S))$ 等于至少出现 1 位属于 $S$ 集合中的概率,等价于 1-一位都不出现的概率.         

出现位数都属于集合 $S$ 的概率等于 $\sum_{j|S=S} p_{j}$,然后这个用 FWT 来一个 or 的正变换即可求出.     

剩下的就按照 min-max 容斥的公式做就行了.   

#include <bits/stdc++.h>    
#define N 21   
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;       
int bin[N],size[1<<N],n;
double p[1<<N],F[1<<N],g[1<<N],A[1<<N],B[1<<N];              
void exi() { printf("INF\n"),exit(0); }
int lowbit(int x) { return x&(-x); }      
void FWT(double *a,int len) 
{
    for(int i=1;i<len;i<<=1) 
        for(int j=0;j<len;j+=i<<1)   
            for(int k=0;k<i;++k) 
                a[j+k+i]+=a[j+k];    
}                    
int main() 
{ 
    // setIO("input");    
    bin[0]=1;   
    for(int i=1;i<N;++i) bin[i]=bin[i-1]<<1;    
    scanf("%d",&n); 
    int is=0,to=bin[n]-1;    
    for(int i=0;i<bin[n];++i) 
    {  
        scanf("%lf",&p[i]),F[i]=p[i];     
        if(p[i]) is|=i;    
    }   
    if(is!=bin[n]-1) 
        exi();            
    for(int i=1;i<bin[n];++i)
        size[i]=size[i-lowbit(i)]+1;          
    FWT(F,bin[n]);    
    double ans=0;     
    for(int i=1;i<bin[n];++i) 
    {            
        double opt=(size[i]%2)?1:-1;              
        ans+=opt/(1.0-F[to^i]);       
    }       
    printf("%.8f\n",ans);    
    return 0;   
}

  

posted @ 2020-05-03 11:39  EM-LGH  阅读(162)  评论(0编辑  收藏  举报