LOJ#2127「HAOI2015」按位或

用$ Min-Max$容斥之后要推的东西少了好多

无耻的用实数快读抢了BZOJLuoguLOJ三个$ OJ$的Rank 1

即将update:被STO TXC OTZ超了QAQ

题意:集合$ [0,2^n)$中每次以一定给出概率产生一个数,求产生数按位或值为$ 2^n-1$的数字数量期望


$ Solution:$

根据$ Min-Max$容斥,令$ Max(S)$表示所有位中最后一次出现的时间,$Min(S)$表示第一次出现的时间

显然有$ ans=Max(S)$

根据$ Min-Max$容斥有

$ Max(S)=sumlimits(-1)^{|T|+1}Min(T)$

现在的问题是如何快速求出$ Min(S)$

由于$ Min(S)$的意义是集合$ S$中第一次出现的位置的出现时间的期望

有每次随机到集合$ S$中某一位的概率为:

$ sumlimits_{T cap S eq emptyset}P_T$

其中$ P_T$是产生$ T$这个数的概率

因此可以得知

$ Min(S)=frac{1}{sumlimits_{T cap S eq emptyset}P_T}$

其中和原集有交可以转化成不属于原集的补集

求原集的补集可以用$ FMT/FWT$优化,时间复杂度$ O(n·2^n)$


$ my code:$

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
    ll x = 0; char zf = 1; char ch = getchar();
    while (ch != '-' && !isdigit(ch)) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}
void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
void writeln(const ll y){write(y);putchar('
');}
int i,j,k,m,n,x,y,z,cnt,tot;
double a[1048577];
namespace fast_IO{
    const int IN_LEN=10000000,OUT_LEN=10000000;
    char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
    inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
    inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
    inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
double readf(){
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    double value=ch-'0';
    ch=getchar();
    while(isdigit(ch)){
        value=value*10+ch-'0';
        ch=getchar();
    }
    if(ch=='.'){
        double cur=0.1;
        ch=getchar();
        while(isdigit(ch)){
            value+=cur*(ch-'0');
            cur*=0.1;
            ch=getchar();
        }
    }
    return value;
}
int main(){
    tot=read();n=1<<tot;
    for(rt i=0;i<n;i++)a[i]=readf();
    for(rt i=0;i<tot;i++)
    for(rt j=0;j<n;j++)if(j>>i&1)a[j]+=a[j^(1<<i)];
    double ans=0;
    for(rt i=0;i<tot;i++)if(a[n-1^(1<<i)]==1)return puts("INF"),0;
    for(rt i=0;i<n;i++)if(a[i]<1-0.0000001){
        if(__builtin_popcount(i)+tot&1)
        ans+=1.0/(1.0-a[i]);else ans-=1.0/(1.0-a[i]);
    }
    printf("%.10f",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/DreamlessDreams/p/10064025.html