P3175 [HAOI2015]按位或
思路
FWT+minmax反演的题目
对于或的FWT,有这样的一个结论\(FWTor[x]=\sum_{i \in x} val[i]\)
然后就是题目了
求所有数都出现的期望时间
对于每个数第一次出现的时间集合,有minmax反演
\[max\{T\}=\sum_{S\in T} (-1)^{|S|+1} min\{S\}
\]
然后对于一个出现概率为\(p_i\)的随机变量,它出现的期望时间是\(\frac{1}{p_i}\)
所以选择到一个集合的时间是\(\frac{1}{1-p_i}\),\(p_i\)是它的子集和,然后用FWT统计子集和即可
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
double p[2000000],ans=0;
int n,lim,sz[2000000],flag=0;
const double eps = 1e-6;
void FWTor(void){
for(int i=2;i<=lim;i<<=1){
int len=i/2;
for(int j=0;j<lim;j+=i)
for(int k=j;k<j+len;k++)
p[k+len]=(p[k+len]+p[k]);
}
}
int main(){
scanf("%d",&n);
lim=(1<<n);
for(int i=0;i<lim;i++)
scanf("%lf",&p[i]);
FWTor();
for(int i=1;i<lim;i++)
sz[i]=(sz[i>>1]+(i&1));
for(int i=1;i<lim;i++){
if(1-p[(lim-1)^i]<eps){
flag=1;
break;
}
ans+=((sz[i]%2)?1:-1)*(1/(1-p[(lim-1)^i]));
}
if(flag)
printf("INF\n");
else
printf("%.10lf\n",ans);
return 0;
}