[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); }
|