zoukankan      html  css  js  c++  java
  • [bzoj 4036][HAOI2015]按位或

    传送门

    Description

    刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行或(c++,c的|,pascal的or)操作。

    选择数字i的概率是p[i]。保证0<=p[i]<=1,Σp[i]=1问期望多少秒后,你手上的数字变成2^n-1。

    Solution

    相当于给你一个集合求最后一个元素出现的时间

    可以用(minmax) 容斥一波,这样就是求每个子集中第一个元素出现的时间(min(T))

    我们设(P(T))表示取到(T)的子集的概率

    [P(min(T)==k)=P(S-T)^{k-1}(1-P(S-T)) ]

    然后因为:

    [若P(x==k)=(1-p)^{k-1}p(k in N^{+}),则E(x)=frac{1}{p} ]

    所以:

    [E(min(T))=frac{1}{1-P(S-T)} ]

    问题在于,如何求(P(T))

    显然

    [P(T)=sum_{x⊆T}p(x),这里我们把一个数都当作一个集合,p(x)就是题目给出的得到x的概率 ]

    求子集和?可以用像「PKUWC2018」随机游走 一样的子集和dp,当然,也可以直接(FWT)变换一下。


    Code 

    #include<bits/stdc++.h>
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    int n,N,num[1<<20];
    double P[1<<20],Ans=0.;
    int main()
    {
        scanf("%d",&n);N=1<<n;
        register int i,j,p,k;
        for(i=0;i<N;++i)scanf("%lf",&P[i]);
        for(i=1;i<N;i<<=1)for(p=i<<1,j=0;j<N;j+=p)for(k=0;k<i;++k) P[i+j+k]+=P[j+k];
        for(i=1;i<N;++i)
    	{
        	num[i]=num[i>>1]+(i&1);
        	if(1-P[(N-1)^i]<1e-9) return 0*puts("INF");
            Ans+=((num[i]&1)?1.:-1.)*(1./(1.-P[(N-1)^i]));
        }
        printf("%.9lf
    ",Ans);
        return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    内存溢出
    接手新业务
    pjb fabu
    中文手册
    人背的时候,做啥都失败
    帮助开发人员学习
    python中的__dict__,__getattr__,__setattr__
    NetCore在Docker中发布及运行
    ELK基础配置
    IdentityServer4 手动验签及日志记录
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10282420.html
Copyright © 2011-2022 走看看