luogu P3175 [HAOI2015]按位或
题面传送门
介绍一下min-max容斥:
\(min(S)=\sum\limits_{T\in S}{(-1)^{|T|+1}max(T)}\)
这个就是考虑除了\(T=max(S)\)的情况其它都能抵消掉,二项式定理证一下就好了。
这个式子似乎没有什么用处,因为一个\(O(n)\)的东西被变成\(O(2^n)\)
但是这个东西在期望意义下也成立,就是说\(E(min(S))=\sum\limits_{T\in S}{(-1)^{|T|+1}E(max(T))}\)
然后这个题就有用,我们要求的就是\(E(max(2^n-1))\)
所以我们其实就是要求\(E(min(S))\)
这个可以认为是\(S\)中第一次出现一个\(1\)
这个时间就是\(\frac{1}{\sum\limits_{i\in S}E(i)}\)
可以FWT搞出来,然后就可以算了,时间复杂度\(O(n2^n)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 20
#define K (1<<N)
#define mod 998244353
#define Mod 998244352
#define eps (1e-4)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
using namespace std;
lb A[K+5],Ans;int n,m,G[K+5];
I void OR(lb *A,int n){
RI i,j,h;for(i=2;i<=n;i<<=1){
for(j=0;j<n;j+=i) for(h=j;h<j+i/2;h++) A[h+i/2]+=A[h];
}
}
int main(){
freopen("1.in","r",stdin);
RI i;scanf("%d",&n);m=(1<<n);for(i=0;i<m;i++) scanf("%Lf",&A[i]);OR(A,m);
for(i=0;i<m;i++) G[i]=G[i>>1]+(i&1),fabs(1-A[(m-1)^i])>=eps&&(Ans+=(G[i]&1?1:-1)*1/(1-A[(m-1)^i]));if(!Ans) puts("INF");else printf("%.10Lf\n",Ans);
}