[洛谷P3175][HAOI2015]按位或

题目大意:刚开始有一个数$x=0$,每秒钟有一个数$y\in[0,2^n)(n\leqslant20)$按一定概率随机出现,数$i$的概率为$p_i$,保证$\sum\limits_{i=0}^{2^n-1}p_i=1$。然后$x\to x|y$,问期望多少时间后,$x=2^n-1$

题解:$Min-Max$容斥
$$
\max(S)=\sum\limits_{T\subseteq S}(-1)^{|T|+1}\min(T)\\
\min(S)=\sum\limits_{T\subseteq S}(-1)^{|T|+1}\max(T)
$$
而且,它在期望下成立,即:
$$
E(\max(S))=\sum\limits_{T\subseteq S}(-1)^{|T|+1}E(\min(T))\\
E(\min(S))=\sum\limits_{T\subseteq S}(-1)^{|T|+1}E(\max(T))
$$
这道题相当于求$E(\max(S))$,也就是说,现在需要求$E(\min(S))$。令$s(S)$表示随机出来的数$y\in S$的概率,即$\sum\limits_{y\in S}p_y$,这可以用$FWT$解决。

求$E(\min(S))$,就枚举选了多少次数与$S$都没有交
$$
\begin{align*}
E(\min(S))&=\sum\limits_{i=0}^{\infty}s(\bar S)^i(i+1)(1-s(\bar S))\\
&=(1-s(\bar S))\dfrac1{(1-s(\bar S))^2}\\
&=\dfrac1{1-s(\bar S)}
\end{align*}
$$
然后$Min-Max$容斥一下就好了

卡点:

 

C++ Code:

#include <algorithm>
#include <cstdio>
#define N 1048576 | 3

int lim, U;
void FWT(double *A) {
	for (int mid = 1; mid < lim; mid <<= 1)
		for (int i = 0; i < lim; i += mid << 1)
			for (int j = 0; j < mid; ++j) A[i + j + mid] += A[i + j];
}

int n;
double p[N], s[N], f[N];
int main() {
	scanf("%d", &n); lim = 1 << n, U = lim - 1;
	for (int i = 0; i < lim; ++i) scanf("%lf", p + i);
	std::copy(p, p + lim, s);
	FWT(s);
	for (int i = 0; i < lim - 1; ++i) if (s[i] == 1) {
		puts("INF");
		return 0;
	}
	for (int i = 1; i < lim; ++i) f[i] = 1 / (1. - s[U ^ i]);

	double ans = 0;
	for (int i = 1; i < lim; ++i) {
		if (__builtin_popcount(i) & 1) ans += f[i];
		else ans -= f[i];
	}
	printf("%.6lf\n", ans);
	return 0;
}

  

posted @ 2019-02-13 16:41  Memory_of_winter  阅读(110)  评论(0编辑  收藏  举报