[BZOJ 4036][HAOI2015]按位或

时间:2023-03-10 03:16:42
[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_{i\operatorname{or}j=k} a_it_j$$

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

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

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

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

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

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

代码实现

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

 #include <bits/stdc++.h>

 const int DWT=;
const int IDWT=-;
const int MAXN=(<<)+; double a[MAXN]; void FWT(double*,int,int); int main(){
int n;
scanf("%d",&n);
int len=<<n;
int cur=;
for(int i=;i<len;i++){
scanf("%lf",a+i);
if(a[i]>)
cur|=i;
}
if(cur!=len-)
puts("INF");
else{
FWT(a,len,DWT);
for(int i=;i<len;i++)
a[i]=1.0/(-a[i]);
FWT(a,len,IDWT);
double ans=;
for(int i=;i<len-;i++)
ans+=a[i];
printf("%.10f\n",ans);
}
return ;
} void FWT(double* a,int len,int opt){
for(int i=;i<len;i<<=)
for(int j=;j<len;j+=i<<)
for(int k=;k<i;k++)
a[j+k+i]+=opt*a[j+k];
}

BZOJ 4036

[BZOJ 4036][HAOI2015]按位或