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

    Description

    (n) 个元素,一共构成 (2^n) 个集合,每个集合 (s) 有一个被选中的概率 (p_s),保证 (sum_{s} p_s=1)。选中一个集合后,集合里所有元素的 tag 变为 1。问期望选多少次集合后,所有元素的 tag 都是 1。

    Solution

    一开始有一个并不正确的做法,认为每一位是独立的,然后计算每一位被打上 tag 的期望时间,然后对所有时间取 max。可以这样理解这个做法的错误所在,期望是对所有情况的平均估计,有些情况下,即使当前这个期望时间最大的元素被打上了 tag,也可能有其他元素没有。所以直接取最大时间是错的。

    正确做法应该是将所有元素当做整体来考虑。(E(max{S})) 表示集合 (S) 中最后一个元素被打上 tag 的期望时间。

    考虑 min-max 容斥,有

    [E(max{S})=sum_{Tsubseteq S} (-1)^{|T|-1} E(min{T}) ]

    (E(min{S})) 即为 (S) 中至少有一个元素被打上标记的期望时间。如果能快速求这个,那么 (E(max{S})) 就能通过 (O(2^n)) 的暴力枚举求出。

    容易发现有

    [E(min{S})=1+E(min{S})sum_{S cap T = emptyset}p_T ]

    整理得到

    [E(min{S})=frac{1}{1-sum_{S cap T = emptyset}p_T} ]

    (S)(T) 交集为空,那么 (T) 一定是 (S) 的补集的子集,所以总系数就是所有子集的概率求和。这个东西可以通过高位前缀和 (O(n2^n)) 预处理出来。那么这道题就做完了,答案就是 (E(max{U}))

    #include<stdio.h>
    #define db double
    
    const int N=20;
    
    int n,p,cnt[1<<N];
    db a[1<<N],ans=0;
    
    int main(){
        scanf("%d",&n); p=1<<n;
        for(int i=0;i<p;i++) scanf("%lf",&a[i]),cnt[i]=cnt[i>>1]+(i&1);
        for(int j=0;j<n;j++)
            for(int i=0;i<p;i++)
                if((1<<j)&i) a[i]+=a[i^(1<<j)];
        for(int i=1;i<p;i++) if(1-a[(p-1)^i]>1e-8) ans+=((cnt[i]&1)? 1:-1)/(1-a[(p-1)^i]);
        if(ans>1e-8) printf("%.8lf",ans);
        else printf("INF");
    }
    
  • 相关阅读:
    分布式事务总结
    正确使用HttpClient,避免出现大量CLOSE_WAIT的TCP链接
    年终总结
    不如自己读一遍AsyncTask源码
    Android支持的图片格式
    Java Annotation Tutorials
    Android中的LruCache
    Hadoop DistributedCache分布式缓存的使用
    Mapreduce设置多路径输入输出
    Ubuntu Server 12.04安装CDH5方法总结
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14903629.html
Copyright © 2011-2022 走看看