[HAOI2015]按位或

[HAOI2015]按位或

是一个 min-max容斥 的板子题。

min-max容斥 式子:

$\displaystyle max(S) = \sum_{T\sube S} (-1)^{|T|+1} min(T)$

并且很优秀的是,它在期望情况下成立!

这个有什么关系呢。。

如果每一位分开考虑,如果第$i$位变成 1 的期望时间是$T(i)$

那么求的是$E(max(T_{1\dots n}))$

这个可以 min-max容斥

求$min$的就是某一个子集让其中某一个变成 1 的期望次数。

考虑一次选择可以让这个子集的某一个变成 1 的概率,就是 1 - 这个子集所有位都是 0 的数字的概率的和,可以考虑令$S$是除了子集的位是0其他都是1的数(集合),概率就是$1 - \sum_{A[i] \sube S} p_i$每次选择是等价的,所以期望就是$\frac{1}{p}$

然后minmax容斥式子种$|T|$其实就是$S$中 0 的个数,就是n - popcount

这个的计算其实就是半个 或卷积

复杂度$O(n2^n)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
#define MAXN ( 1 << 21 ) + 6
int n;
double p[MAXN];

inline void FWT(double a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
a[j + (mid >> 1)] += a[j];
}

int main() {
cin >> n;
for( int i = 0 ; i < ( 1 << n ) ; ++ i ) scanf("%lf",&p[i]);
FWT( p , ( 1 << n ) );
double ans = 0.0;
for( int i = 0 ; i < ( 1 << n ) - 1; ++ i ) {
ans += ( ( n - __builtin_popcount( i ) & 1 ) ? 1.0 : -1.0 ) / ( 1.0 - p[i] );
}
if( ans > 1e50 ) puts("INF");
else printf("%.7lf",ans);
}
文章作者: yijan
文章链接: https://yijan.co/old48/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog