P3175 [HAOI2015]按位或(max-min 容斥)
max-min 容斥:
设 \(\max(S)\) 为 \(S\) 中的最大元素,\(\min(S)\) 为 \(S\) 中的最小元素,则有:
考虑证明,对于 \(S\) 中第 \(k\) 大的数 \(x_k\) 建立映射 \(f(x_k)=\{1,2\cdots k\}\)
于是对于两数 \(a,b\),有 \(f(\max(a,b))=f(a)\cup f(b),f(\min(a,b))=f(a)\cap f(b)\)
那么以第一个式子为例
由于这显然是个一一映射,所以 \(|f(\min(T))|\) 就可以映射回 \(\min(T)\),于是就证明了这个式子
这个式子在期望下也成立:
它的变形还可以在第 \(k\) 大,以及第 \(k\) 大的期望下成立:
当然以上对于 \(\min\) 的情况也是同理
就不证明了
此题 就用到了在期望下的式子
用 \(S\) 表示 \(2^n-1\) 每一个二进制位的集合,\(\max(S)\) 表示其中出现最晚的位置的出现时间,\(\min(S)\) 则是出现最早的位置的出现时间
要求的显然是 \(E(\max(X))\),\(X\) 为 \(n\) 个二进制位的全集
那么由 \(E(\max(S))=\sum_{T \subseteq S}(-1)^{|T|-1} E(\min(T))\),问题就变成了如何求 \(E(\min(T))\)
对于任意集合 \(U,U\cap T\neq \varnothing\),只要 \(U\) 被加入,\(T\) 就有了“最早出现的位置”,于是每次取数能出现这样的位置的概率就是所有满足要求的 \(U\) 的概率和,那么期望就是再取倒数:
但是这样的 \(U\) 不太好求,考虑取 \(T\) 的补集 \(G\),那么 \(U\) 显然就是 \(G\) 的子集,于是用 FWT 的方法求出每个子集和就行了
#include<cstdio>
#include<cmath>
#define reg register
#define LL_INF (long long)(0x3f3f3f3f3f3f3f3f)
#define INT_INF (int)(0x3f3f3f3f)
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
return y?x:-x;
}
#define N 1048588
int n;
double p[N];
int cnt[N];
inline void FWT(){
for(reg int o=2,k=1;o<=n;o<<=1,k<<=1){
for(reg int i=0;i<n;i+=o)for(reg int j=0;j<k;j++) p[i+j+k]+=p[i+j];
}
}
int main(){
n=(1<<read());
for(reg int i=0;i<n;i++) scanf("%lf",p+i),cnt[i]=cnt[i>>1]+(i&1);
FWT();
double ans=0;
for(reg int i=1;i<n;i++) ans+=((cnt[i]&1)?1:-1)/(1-p[i^(n-1)]);
if(ans>1e20) puts("INF");
else printf("%lf\n",ans);
return 0;
}