• [HAOI2015]按位或(容斥+前缀和)


    题目描述

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

    大概就是这么两个东西,做题思路大概就是正难则反吧,max不好求但min好求,就可以直接用这种方法上了。

    现在我们算maxV(S),然鹅它不好算,所以我们就转换求所有minV(S)。

    考虑一个事件发生的概率为p,那么我们就有了求min的方法。

    sum=1*p+2*(p-1)*p+3*(p-1)^2*p......

    然后用高中数学知识,解得它等于1/p。

    然后我们的任务变成了求所有子集的p。

    这玩意也不太好求,因为所有与这个集合有交的数都会产生贡献。

    再次正难则反一下,变成了1-补集,这个补集和很好,它就是补集的高维前缀和。

    有人说这是FMT,但好像FWT的异或卷积也长这样?

    代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define N (1<<20)+20
    using namespace std;
    const double eps=1e-10;
    int n,size,cnt[N];
    double ans,a[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(f=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x; 
    } 
    int main(){
        n=rd();size=(1<<n);int up=size;
        for(int i=0;i<size;++i)scanf("%lf",&a[i]); 
        for(int i=1;i<size;i<<=1)
            for(int j=0;j<size;++j)if(!(j&i))a[j|i]+=a[j];
        for(int i=1;i<=size;++i)cnt[i]=cnt[i>>1]+(i&1);
        for(int i=1;i<size;++i){
            double x=1-a[(size-1)^i];
            if(fabs(x)<eps){printf("INF
    ");return 0;}
            if(cnt[i]&1)ans+=(double)1/x;else ans-=(double)1/x;
        }
        printf("%.10lf",ans);
        return 0;
    }

    我看到网上还有这么一种解法

    然而我并没有看懂。。。

  • 相关阅读:
    liststyle
    :nthchild(n)
    织梦CMS首页调用分类信息栏目及列表方法
    []织梦CMS首页调用分类信息栏目及列表方法
    ps快捷键
    系统架构博客,很不错
    google maps api 反向解析 地址 api
    sphinx
    sphinx discuss
    ruby分词
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10222235.html
Copyright © 2020-2023  润新知