【洛谷P3175】按位或
题目
题目链接:https://www.luogu.com.cn/problem/P3175
刚开始你有一个数字 \(0\),每一秒钟你会随机选择一个 \([0,2^n-1]\) 的数字,与你手上的数字进行或(C++,C 的 |
,pascal 的 or
)操作。选择数字 \(i\) 的概率是 \(p_i\)。保证 \(0\leq p_i \leq 1\),\(\sum p_i=1\) 。问期望多少秒后,你手上的数字变成 \(2^n-1\)。
思路
设 \(S\) 为全集 (\(S=\{x|0\leq x<2^n\}\)),设 \(E(x)\) 表示 \(x\) 被包含于得到的数字数字的期望次数,根据 min-max 容斥,有
\[E(\max(S))=\sum_{T\in S}(-1)^{|T|+1}E(\min(T))
\]
其中 \(E(\max(S))=E(2^n-1)\) 即为我们所求。
考虑如何求出 \(E(\min(T))\)。显然 \(E(\min(T))\) 等于“一直在 \([0,2^n-1]\) 中随机取数,直到取到一个数 \(x\ \mathrm{and}\ T\neq \varnothing\) 的期望次数”。
设 \(f(T)\) 表示在 \([0,2^n-1]\) 中随机取数,取到 \(T\) 子集内的数的期望。那么
\[f(T)=\frac{1}{\sum_{x\in T}p(x)}
\]
这个东西就是子集卷积,直接上 FWT 即可。
那么
\[E(\min(T))=\frac{(f(T\ \mathrm{xor}\ S)E(\min(T))+1)+1}{2}=\frac{1}{1-f(T\ \mathrm{xor}\ S)}
\]
这样就在 \(O(2^nn)\) 内搞定了这道题。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=(1<<20)+10;
const double eps=1e-12;
int n,lim,bit[N];
double ans,p[N];
int main()
{
scanf("%d",&n);
lim=(1<<n);
for (int i=0;i<lim;i++)
scanf("%lf",&p[i]);
for (int k=1;k<lim;k<<=1)
for (int i=0;i<lim;i+=(k<<1))
for (int j=0;j<k;j++)
p[i+j+k]+=p[i+j];
for (int i=0;i<lim-1;i++)
{
if (1-p[i]<eps) return printf("INF"),0;
p[i]=1.0/(1-p[i]);
}
for (int i=1;i<lim;i++)
{
bit[i]=bit[i^(i&-i)]+1;
ans+=((bit[i]&1)?1.0:-1.0)*p[lim-1-i];
}
printf("%.10lf",ans);
return 0;
}