P3175 [HAOI2015]按位或

思路

FWT+minmax反演的题目
对于或的FWT,有这样的一个结论\(FWTor[x]=\sum_{i \in x} val[i]\)
然后就是题目了
求所有数都出现的期望时间
对于每个数第一次出现的时间集合,有minmax反演

\[max\{T\}=\sum_{S\in T} (-1)^{|S|+1} min\{S\} \]

然后对于一个出现概率为\(p_i\)的随机变量,它出现的期望时间是\(\frac{1}{p_i}\)
所以选择到一个集合的时间是\(\frac{1}{1-p_i}\)\(p_i\)是它的子集和,然后用FWT统计子集和即可

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
double p[2000000],ans=0;
int n,lim,sz[2000000],flag=0;
const double eps = 1e-6;
void FWTor(void){
    for(int i=2;i<=lim;i<<=1){
        int len=i/2;
        for(int j=0;j<lim;j+=i)
            for(int k=j;k<j+len;k++)
                p[k+len]=(p[k+len]+p[k]);
    }
}
int main(){
    scanf("%d",&n);
    lim=(1<<n);
    for(int i=0;i<lim;i++)
        scanf("%lf",&p[i]);
    FWTor();
    for(int i=1;i<lim;i++)
        sz[i]=(sz[i>>1]+(i&1));
    for(int i=1;i<lim;i++){
        if(1-p[(lim-1)^i]<eps){
            flag=1;
            break;
        }
        ans+=((sz[i]%2)?1:-1)*(1/(1-p[(lim-1)^i]));
    }
    if(flag)
        printf("INF\n");
    else
        printf("%.10lf\n",ans);
    return 0;
}

posted @ 2019-06-11 15:12  dreagonm  阅读(194)  评论(0编辑  收藏  举报