[HAOI2015]按位或 min-max容斥+FWT

版权声明:本文是蒟蒻写的,转载。。。随便吧 https://blog.csdn.net/xgc_woker/article/details/85953329

Description
刚开始你有一个数字 0 0 ,每一秒钟你会随机选择一个 [ 0 , 2 n 1 ] [0,2^n-1] 的数字,与你手上的数字进行或操作。选择数字i的概率是 p [ i ] p[i] 。保证 0 < = p [ i ] < = 1 0<=p[i]<=1 p [ i ] = 1 \sum p[i]=1 问期望多少秒后,你手上的数字变成 2 n 1 2^n-1


Sample Input
2
0.25 0.25 0.25 0.25


Sample Output
2.6666666667


关于 m i n m a x min-max 容斥的一点东西:
m i n m a x min-max 容斥的模型:给出n个数出现的概率,求所有数出现一次的期望次数。
设一个元素的大小为这个元素出现的时间。
m i n ( S ) min(S) 为集合中最小的元素。
m a x ( S ) max(S) 为集合中最大的元素。
P P 为概率, E E 为期望次数。
可知 P ( m i n ( S ) ) = i S P i P(min(S))=\sum_{i \in S}Pi
E ( m i n ( S ) ) = 1 P ( m i n ( S ) ) E(min(S))=\frac 1{P(min(S))}
对于模型,我们需要求解的实际上是 E ( m a x ( S ) ) E(max(S))
那么就有一个式子:
E ( m a x ( S ) ) = T S E ( m i n ( T ) ) ( 1 ) T + 1 E(max(S))=\sum_{T \subset S}E(min(T))*(-1)^{|T|+1}

回到这道题,考虑求出 E ( m i n ( S ) ) E(min(S))
那么只要与 S S 有交集其实对 S S 就是有贡献的。
那么这个东西实际上不是很好求。
把他反过来就相当于求补集的子集,这个可以FWT解决。


#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

#define eps 1e-8
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

int n, cnt[1 << 20];
double ans, P[1 << 20];

int main() {
	int n = read(); int N = 1 << n;
	for(int i = 0; i < N; i++) scanf("%lf", &P[i]), cnt[i] = cnt[i >> 1] + (i & 1);
	for(int i = 1; i < N; i <<= 1) {
		for(int j = 0; j < N; j += i << 1) {
			for(int k = 0; k < i; k++) {
				P[j + k + i] += P[j + k];
			}
		}
	} ans = 0;
	for(int i = 0; i < N; i++) if(1.0 - P[i ^ (N - 1)] > eps) 
	ans += (cnt[i] & 1 ? 1 : -1) / (1.0 - P[i ^ (N - 1)]);
	if(ans < eps) puts("INF"); else printf("%.8lf\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/85953329