zoukankan      html  css  js  c++  java
  • BZOJ4036:按位或 (min_max容斥&高维前缀和)

    Description

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

    Input

    第一行输入n表示n个元素,第二行输入2^n个数,第i个数表示选到i-1的概率

    Output

    仅输出一个数表示答案,绝对误差或相对误差不超过1e-6即可算通过。如果无解则要输出INF

    Sample Input

    2
    0.250.250.250.25

    Sample Output

    2.6666666667

    HINT

     对于100%的数据,n<=20

    思路:可以min_max容斥来做,问题的关键就是求出得到所有子集X的期望F(X)就可以了,P(X)的概率为所有对X有贡献的p[x]之和(x是所有和X有交集的x,即便x含有X没有的部分);

    我们倒过来求与X交集为空的部分的概率,即M^X的子集的概率,这部分可以用高维前缀和来做。

        for(int i=0;i<N;i++)
         for(int j=0;j<(1<<N);j++)
            if(j&(1<<i)) F[j]+=F[j^(1<<i)];
    这个代码可以得到子集的前缀和。 复杂度是O(N*2^N)

     超集的写法:

        for(int i=0;i<N;i++)
         for(int j=0;j<(1<<N);j++)
            if(!j&(1<<i)) F[j]+=F[j|(1<<i)];
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1<<21;
    double P[maxn],ans;int N,sum,M;
    void dfs(int pos,int now,int cnt)
    {
        if(pos==N){
            if(cnt>=1){
                if(cnt&1) ans+=1.0/(1.0-P[(M-1)^now]);
                else ans-=1.0/(1.0-P[(M-1)^now]);
            }
            return ;
        }
        dfs(pos+1,now|(1<<pos),cnt+1);
        dfs(pos+1,now,cnt);
    }
    int main()
    {
        scanf("%d",&N); M=1<<N;
        for(int i=0;i<M;i++){
             scanf("%lf",&P[i]);
             if(P[i]>0) sum|=i;
        }
        if(sum!=M-1) return  puts("INF"),0;
        for(int i=0;i<N;i++)
         for(int j=0;j<M;j++)
            if(j&(1<<i)) P[j]+=P[j^(1<<i)];
        dfs(0,0,0);
        printf("%.6lf
    ",ans);
        return 0;
    }
    //2 0.25 0.25 0.25 0.25

    当然,为1的个数我们也可以预处理出来。就不用DFS了。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1<<21;
    double P[maxn],ans;int N,sum,M,num[maxn];
    int main()
    {
        scanf("%d",&N); M=1<<N;
        for(int i=0;i<M;i++){
             scanf("%lf",&P[i]);
             if(P[i]>0) sum|=i;
        }
        if(sum!=M-1) return  puts("INF"),0;
        for(int i=1;i<M;i++) num[i]=num[i>>1]+(i&1);
        for(int i=0;i<N;i++)
         for(int j=0;j<M;j++)
            if(j&(1<<i)) P[j]+=P[j^(1<<i)];
        for(int i=1;i<M;i++)
            ans+=(num[i]&1?1.0:-1.0)/(1-P[(M-1)^i]);
        printf("%.6lf
    ",ans);
        return 0;
    }
    //2 0.25 0.25 0.25 0.25
  • 相关阅读:
    C++基础学习6:内联函数
    lvm
    yum源
    mysql性能优化
    PXE
    dns配置
    进程命令
    ssh免密登陆和加密解密
    RAID阵列
    快速部署postfix邮件服务器
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9947024.html
Copyright © 2011-2022 走看看