[HAOI2015]按位或

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

2
0.25 0.25 0.25 0.25

输出样例#1:

2.6666666667

说明

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

题解

\(min_max\)容斥+高维前缀和
先说一下一点前置知识
\(min\_max\)容斥:
对于一个集合\(S\),\(max(S)\)表示\(S\)集合中最大的元素,\(min(S)\)表示\(S\)集合中最小的元素
那么

\(max(S)=\sum_{T \subset S}(-1)^{|T|+1}min(T)\)
\(min(S)=\sum_{T\subset S}(-1)^{|T|+1}max(T)\)

这玩意儿具体说起来比较麻烦,大致就是每种子集的极小/大值互相都消掉了,最后就剩下了\(T=\{max(S)\}\)这一项且前面的容斥系数是1

还有就是如果一个东西每步出现的概率为\(p\),那么这个东西出现的期望步数就是\(\frac{1}{p}\)

然后再搞这个题:
首先\(min\_max\)容斥是可以用在期望中的
我们设\(E(max(S))\)表示集合\(S\)中期望出现时间最大的元素的出现时间,也就是这个集合所有元素都出现的期望时间
\(E(min(S))\)表示集合\(S\)中期望出现时间最小的元素的出现时间
发现答案就是\(E(max(U))=\sum_{S\subset U}{(-1)^{|S|+1}E(min(S))}\)
那么我们就枚举\(U\)的子集\(S\)
我们要计算\(E(min(S))\)比较困难
但是因为\(E(min(S))\)要保证之前出现的元素集合不能与\(S\)有交
所以我们可以反面计数
计算\(S\)的补集出现的概率\(p\)
那么\(S\)出现的概率就是\(1-p\)
那么\(S\)的期望步数就是\(\frac{1}{1-p}\)
那么答案就是\(\sum_{S\subset U}\frac{(-1)^{|S|+1}}{1-p}\)

代码

#include<cstdio>
#include<algorithm>
const int M = (1 << 20) + 5 ;
const double EPS = 1e-10 ;
using namespace std ;

int n , lim , cnt[M] ; 
double p[M] , f[M] , ans ;
int main() {
    scanf("%d",&n) ; lim = (1 << n) ;
    for(int i = 1 ; i < lim ; i ++) cnt[i] = cnt[i >> 1] + (i & 1) ;
    for(int i = 0 ; i < lim ; i ++) scanf("%lf",&p[i]) ;
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j < lim ; j ++)
            if(j & (1 << (i - 1)))
                p[j] += p[j ^ (1 << (i - 1))] ;
    for(int i = 1 ; i < lim ; i ++)
        if(1 - p[(lim - 1) ^ i] > EPS)
            ans += ((cnt[i] & 1) ? 1 : -1) / (1 - p[(lim - 1) ^ i]) ;
    if(ans < EPS) printf("INF\n") ; else printf("%.10lf\n",ans) ;
    return 0 ;
}

转载于:https://www.cnblogs.com/beretty/p/10687579.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值