[BZOJ 4036][HAOI2015]按位或

4036: [HAOI2015]按位或

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 746  Solved: 456
[Submit][Status][Discuss]

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.25 0.25 0.25 0.25

Sample Output

2.6666666667

HINT

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

题解

首先无解非常好判. 非 $0$ 概率值全都或起来如果得不到全集就肯定无解了.

这题要求期望...考虑期望等于啥...

每步开始之前, 我们对于非全集的情况都需要继续进行下一步.

由期望的线性性, 我们可以对于每一步都分开计算.

而进行完一步之后每种状态的概率要怎么算呢? 显然我们有:

$$ c_k=sum_{ioperatorname{or}j=k} a_it_j$$

显然这是一个或运算卷积的形式. 所以对于一步的情况, 我们可以FWT解决.

但是在这个题目里则可能是无限步, 我们继续来思考.

因为FWT满足卷积定理, 所以我们有:

$$ operatorname{FWT}left(sum_{i=0}^infty t^i ight)_k=sum_{i=0}^infty operatorname{FWT}(t)_k^i $$

而等式右边是个首项为 $1$ 的等比数列求和式, 因为 $operatorname{FWT}(t)_kleq 1$ 所以这个值一定收敛于 $frac 1 {1-operatorname{FWT}(t)_k}$.

算完 $operatorname{FWT}^{-1}$ 回去求所有非全集下标的和就行了.

代码实现

毕姥爷: 从我们都熟悉的FWT开始

 1 #include <bits/stdc++.h>
 2 
 3 const int DWT=1;
 4 const int IDWT=-1;
 5 const int MAXN=(1<<20)+233;
 6 
 7 double a[MAXN];
 8 
 9 void FWT(double*,int,int);
10 
11 int main(){
12     int n;
13     scanf("%d",&n);
14     int len=1<<n;
15     int cur=0;
16     for(int i=0;i<len;i++){
17         scanf("%lf",a+i);
18         if(a[i]>0)
19             cur|=i;
20     }
21     if(cur!=len-1)
22         puts("INF");
23     else{
24         FWT(a,len,DWT);
25         for(int i=0;i<len;i++)
26             a[i]=1.0/(1-a[i]);
27         FWT(a,len,IDWT);
28         double ans=0;
29         for(int i=0;i<len-1;i++)
30             ans+=a[i];
31         printf("%.10f
",ans);
32     }
33     return 0;
34 }
35 
36 void FWT(double* a,int len,int opt){
37     for(int i=1;i<len;i<<=1)
38         for(int j=0;j<len;j+=i<<1)
39             for(int k=0;k<i;k++)
40                 a[j+k+i]+=opt*a[j+k];
41 }
BZOJ 4036

日常图包

原文地址:https://www.cnblogs.com/rvalue/p/10242551.html