1. 程式人生 > >[BZOJ 4036][HAOI2015]按位或

[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開始

 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\n",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

日常圖包