bzoj4036 / P3175 [HAOI2015]按位或

bzoj4036 / P3175 [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) $

#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);
}
posted @ 2019-12-28 11:37  yijan  阅读(85)  评论(0编辑  收藏  举报