I.[HAOI2015]按位或
在本题中,(minmathbb S) 表示 (mathbb S) 中第一个被取到的位置被取到的时间,(maxmathbb S) 表示最后一个被取到的位置被取到的时间。则我们要求的就是 ( ext E(maxmathbb S))。
现在,考虑计算 ( ext E(minmathbb T))。
设 (P(mathbb S)) 表示选一个数,是 (mathbb S) 子集的概率。显然,这个东西可以通过FMT简单求出。
则,(minmathbb T=i) 的概率就是
[P(mathbb{Ssetminus T})^{i-1}Big(1-P(mathbb{Ssetminus T})Big)
]
这里的 (setminus) 符号是集合删除符号。因为 (mathbb T) 中只要取到一个就算成功,所以前 (i-1) 次都必须在 (mathbb T) 的补集里取,而最后一次不能在 (mathbb T) 的补集里取。为了简便,我们此处设 (p=P(mathbb{Ssetminus T}))。则要求
[sumlimits_{i=1}ip^{i-1}(1-p)
]
将其转换为
[(1-p)sumlimits_{i=1}ip^{i-1}
]
其是等差数列与等比数列之积的形式。故我们设 (A=sumlimits_{i=1}ip^{i-1}),则 (pA=sumlimits_{i=1}ip^i=sumlimits_{i=2}(i-1)p^{i-1}=sumlimits_{i=1}(i-1)p^{i-1})。计算 (A-pA),得到 (sumlimits_{i=1}p^{i-1}),其等于 (dfrac{1}{1-p})。故 ((1-p)A=dfrac{1}{1-p}),即 (A=dfrac{1}{(1-p)^2})。再乘上最外面的 (1-p),得到公式
[ ext E(minmathbb T)=dfrac1{1-P(mathbb{Ssetminus T})}
]
直接容斥即可。时间复杂度 (O(n2^n)),瓶颈在于FMT。
代码为了图方便,直接枚举了 (mathbb{Ssetminus T})。
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-10;
int n,m;
double f[1<<20],res;
int main(){
scanf("%d",&n),m=1<<n;
for(int i=0;i<m;i++)scanf("%lf",&f[i]);
for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(j&(1<<i))f[j]+=f[j^(1<<i)];
for(int i=0;i<m-1;i++){
if(f[i]+eps>1){puts("INF");return 0;}
if(__builtin_popcount((m-1)^i)&1)res+=1/(1-f[i]);else res-=1/(1-f[i]);
}
printf("%.10lf
",res);
return 0;
}