zoukankan      html  css  js  c++  java
  • 【BZOJ4036】按位或(HAOI2015)-Min-Max容斥+FWT

    测试地址:按位或
    做法:本题需要用到Min-Max容斥+FWT。
    因为一直是或,所以一个位置上如果有了1,这个1就会一直有下去,那么问题就变成了,每次选择一个子集,问所有点都被选过的期望次数。所有点都被选过的期望次数,也就相当于这些点中最后一个点被选的期望次数,容易想到Min-Max容斥:
    E[max{S}]=TS(1)|T|+1E[min{T}]
    那么现在问题就变成如何求E[min{T}]了。注意到这个期望相当于,这些点中第一次被取到的期望次数,也就等于这些点被取到的概率的倒数。直接统计被取到的概率较难,考虑补集转化,变成求不被取到的概率,容易发现这就是所有ST的子集的概率和,记为P(ST)。于是问题就变成快速求出所有集合的P
    显然直接枚举计算是O(3n)的,无法承受。这时我们看到标题里有一个FWT(这个引入太牵强了吧……),可是这里并没有出现位运算卷积之类的东西啊……
    别被套进去了,谁说FWT只是拿来求位运算卷积的了?在关于或运算的FWT中,我们通过正变换可以得到bi=j|i=iaj。等等,仔细一想,这不就是求集合i所有子集jaj和吗?于是我们用FWT来解决这个问题,时间复杂度为O(n2n),而后面枚举集合就是O(2n)的了,可以通过此题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int m,n;
    double p[1500010];
    
    void FWT(double *a)
    {
        for(int mid=1;mid<n;mid<<=1)
            for(int l=0;l<n;l+=(mid<<1))
                for(int k=0;k<mid;k++)
                {
                    double x=a[l+k],y=a[l+mid+k];
                    a[l+k]=x;
                    a[l+mid+k]=x+y;
                }
    }
    
    int main()
    {
        scanf("%d",&m);
        n=(1<<m);
        for(int i=0;i<n;i++)
            scanf("%lf",&p[i]); 
    
        FWT(p);
        double ans=0.0;
        for(int i=1;i<n;i++)
        {
            double cnt=-1.0;
            int x=i;
            while(x) x-=(x&(-x)),cnt=-cnt;
            if (1.0-p[n-i-1]<1e-8) {printf("INF");return 0;}
            ans+=cnt/(1.0-p[n-i-1]);
        }
        printf("%.10lf",ans);
    
        return 0;
    }
  • 相关阅读:
    SQLServer存储过程实现单条件分页
    AJAX遮罩实例
    JS获取网站StatusCode,若存在写入文件
    AJAX同步和异步的区别
    通过JS将BSAE64生成图片并下载
    Bootstrap学习-排版-表单
    Bootstrap学习-环境安装
    这才是你需要的最基础的.Net基础面试题(通俗易懂,最基础的.Net)
    这才是你需要的最基础的.Net基础面试题(通俗易懂,最基础的.Net)
    这才是你需要的最基础的.Net基础面试题(通俗易懂,最基础的.Net)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793297.html
Copyright © 2011-2022 走看看