版权声明:本文是蒟蒻写的,转载。。。随便吧 https://blog.csdn.net/xgc_woker/article/details/85953329
Description
刚开始你有一个数字
,每一秒钟你会随机选择一个
的数字,与你手上的数字进行或操作。选择数字i的概率是
。保证
,
问期望多少秒后,你手上的数字变成
。
Sample Input
2
0.25 0.25 0.25 0.25
Sample Output
2.6666666667
关于
容斥的一点东西:
容斥的模型:给出n个数出现的概率,求所有数出现一次的期望次数。
设一个元素的大小为这个元素出现的时间。
设
为集合中最小的元素。
为集合中最大的元素。
设
为概率,
为期望次数。
可知
,
。
对于模型,我们需要求解的实际上是
。
那么就有一个式子:
回到这道题,考虑求出
。
那么只要与
有交集其实对
就是有贡献的。
那么这个东西实际上不是很好求。
把他反过来就相当于求补集的子集,这个可以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;
}