• P3175 [HAOI2015]按位或 FMT Min-Max容斥


    题意:

    戳这里

    分析:

    • 前置芝士:Min-Max容斥,FMT,离散型随机变量的几何分布
    1. Min-Max容斥:

    式子:(displaystyle max(S)=sum_{Tsubset S}(-1)^{|T|+1}min(T))

    其中 (min max) 可以互换位置 , 而且最重要的是 Min-Max容斥 在期望形式下仍成立

    简单证明:

    我们记 S 中最大的数为 (x) ,那么只要证明除 (x) 以外的数都被消掉了即可

    首先 (min(T)==x) 当且仅当 (T={x}) 的时候才成立,所以 (x) 的系数恒为 (1)

    其次,我们记 (y)(S) 中排名第 (K) 的数,那么 (min(T)==y) 的方案数为 (2^{n-k}) 中,其中一半的 (T) 大小为奇数,一半的 (T) 大小为偶数,所以相互抵消之后,(y) 的系数为 (0)

    1. 离散型随机变量的几何分布

    首先定义一个离散型随机变量满足几何分布的形式为,(P(x==k)=(1-p)^{k-1}p (kin N^+)) 其中 p 为一个常量参数

    然后我们要推一下柿子来求这个服从几何分布的离散型随机变量的期望,我们记离散型随机变量为 (X)

    [E(x)=sum_{i=1}^{infty} iP(X==i) \ =sum_{i=1}^{infty} i(1-p)^{i-1}p \ =psum_{i=1}^{infty}i(1-p)^{i-1} \ =psum_{i=0}^{infty} [(1-p)^i]' \ =p [ sum_{i=0}^{infty}(1-p)^i ]' \ =p [frac{1}{1-(1-p)}]' \ =pfrac{1}{p^2} \ =frac{1}{p} ]

    所以我们得到了一个很有用的结论,就是满足几何分布的离散型随机变量的期望等于服从参数的倒数

    1. FMT(快速莫比乌斯变换)

    和 FFT 的思想差不多,不过 FFT 是和卷积,而 FMT 是按位或卷积,这里给出 FMT 的定义式:

    (displaystyle hat f(x) = sum_{isubset x}f(i))

    和 FFT 一样,FMT 可以分治计算,而且不需要乘上一堆奇奇怪怪的参数 (a[i+j]=a[i+j],a[i+j+len]=a[i+j+len])


    我们把每一位看成一个元素,它的值等于它变成一的期望步数

    我们要求的的东西可以转化为,(displaystyle E(max(S))=sum_{Tsubset S}(-1)^{|T|+1}E(min(T)))

    其中 (min max) 表示达到这个状态所需要最大步数的元素的步数,感性理解一下,当最大步数的元素都变成了 (1) 以后,其他元素也都变成了 (1)

    然后我们 容易发现,(min()) 作为一个离散型随机变量,是满足几何分布的,我们记 (S) 的补集为 (R) ,一个集合选出一个元素属于它的概率为 (H) ,那么柿子如下:

    [H(S)=1-sum_{Tsubset R}H(T) \ P(min(S)==k)=(1-H(S))^{k-1}H(S) \ E(min(S))=frac{1}{1-sum_{Tsubset R}H(T)} ]

    然后我们整理一下思路,具体步骤就是:

    1. FMT 求出 (H())
    2. Min-Max 容斥求 (E(max (S)))

    代码:

    代码真短,让我们一起赞美良心出题人吧!

    #include<bits/stdc++.h>
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
        const int maxn = (1<<20)+5;
        const double eps = 1e-10;
        int n,lim;
        int cnt[maxn];
        double ans;
        double a[maxn];
    
        void work()
        {
            scanf("%d",&n);lim=(1<<n);
            for(int i=0;i<lim;i++) scanf("%lf",&a[i]);
            for(int len=1;len<lim;len<<=1)
                for(int i=0;i<lim;i+=(len<<1))
                    for(int j=i;j<i+len;j++) a[j+len]+=a[j];
            for(int i=1;i<lim;i++) cnt[i]=cnt[i>>1]+(i&1);
            for(int i=1;i<lim;i++)
            {
                if(1.0-a[(lim-1)^i]<eps) 
                {
                    puts("INF");
                    return ;
                }
                double tmp=1.0/(1.0-a[(lim-1)^i]);
                if(cnt[i]&1) ans+=tmp;
                else ans-=tmp;
            }
            printf("%.7f
    ",ans);
        }
    
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    linux shell 中"2>&1"含义-完美理解-费元星
    浅谈移动端设备标识码:DeviceID、IMEI、IDFA、UDID和UUID -费元星
    费元星-关于百度在数据仓库-层级架构上的思考
    费元星的第二代车,基于图像识别和超声波的无人智能小车
    【完美解决】Spark-SQL、Hive多 Metastore、多后端、多库
    【费元星】crt 无法上传文件,总是显示盾牌表示-完美解决
    【费元星原创】一键安装Hadoo2.7.6 集群完全分布式脚本-完美解决
    【研发工具必备】费元星的技术成长流线图-第一版
    【shell mysql 导出数据到csv脚本,完美解决乱码转义符等问题】-费元星
    【Linux搭建创建FTP服务器】---完美解决
  • 原文地址:https://www.cnblogs.com/youth518/p/14339591.html
Copyright © 2020-2023  润新知