• P3175-[HAOI2015]按位或【min-max容斥,FWT】


    正题

    题目链接:https://www.luogu.com.cn/problem/P3175


    题目大意

    开始有一个(n)位二进制数(s=0),每次有(p_i)概率选取数字(i)(s)或上这个数字(i),求期望多少次能够让(s)(n)个位都变为(1)


    解题思路

    因为是或所以我们只关心最后一个选中的数,设第(i)位选中的期望次数为(E(i))的话答案就是(max{E(i)})

    又是期望又是(max)所以可以直接上( ext{min-max})容斥,答案就是

    [sum_{Tin S}min{E(i)}(iin T)*(-1)^{|T|+1} ]

    算这个东西的话也就是如果我们选中一个与(T)有交集的数就可以退出了。期望次数=1/期望概率。所以我们直接算期望概率

    也就是我们要算所有(sum_{Gcap T eq varnothing}p_{G})(G)(T)的交集非空就去掉所有交集为空的,交集为空的就是(T)的补集的子集和。

    子集和的话就是直接拿(p)出来跑一次(or)( ext{FWT})的结果就是子集和了。

    时间复杂度(O(n2^n))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N=1<<21;
    const double eps=1e-8;
    int n;double cnt[N],p[N],ans;
    void FWT_or(double *f,int op){
        for(int p=2;p<=n;p<<=1)
            for(int k=0,len=p>>1;k<n;k+=p)
                for(int i=k;i<k+len;i++)
                    f[i+len]+=f[i]*op;
        return;
    }
    int main()
    {
        scanf("%d",&n);
        cnt[0]=-1;n=1<<n;
        for(int i=0;i<n;i++)
            scanf("%lf",&p[i]);
        FWT_or(p,1);
        for(int i=0;i<n;i++){
            if(i)cnt[i]=-cnt[i-(i&-i)];
            double e=1-p[(n-1)^i];
            if(fabs(e)<eps)continue;
            ans+=cnt[i]*(1.0/e);
        }
        if(ans<eps)printf("INF");
        else printf("%.10lf",ans);
    }
    
  • 相关阅读:
    Jvm年轻代复制到Survivor To区时,对象存放不下会发生什么?
    Jvm内存布局和Java对象内存布局
    ArrayList的removeIf和iterator.remove性能比较
    闲着没事做,用js做了一个冒泡排序的动画
    对象与this
    idea 简记
    线程按序交替
    大数阶乘
    序列化 与 反序列化
    人月神话
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14275459.html
Copyright © 2020-2023  润新知