题解 luogu P3715 [HAOI2015]按位或
【分析】
由拓展 min-max 容斥得:\(\displaystyle \text{k-thmax}(S)=\sum_{T\subseteq S}(-1)^{|T|-k}\binom {|T|-1}{k-1}\min(S)\)
故本题认为 \(\max(S)\) 表示选择若干个数字或起来后,数字 \(S\) 的最后一位出现时间的随机变量
同理,\(\min(S)\) 表示选择若干个数字或起来后,数字 \(S\) 的第一位出现时间的随机变量
故 \(\displaystyle E(\max(S))=\sum_{\varnothing\subset T\subseteq S}(-1)^{|T|-1}E(\min(S))\)
而 \(P(\min(S)=k)\) 表明前 \((k-1)\) 次选择的数字都与 \(S\) 不交,且第 \(k\) 次的有交
\(\begin{aligned} \therefore P(\min(S)=k)&=(\sum_{T\cap S=\varnothing} p_T)^{k-1}\cdot (\sum_{T\cap S\neq\varnothing} p_T) \\&=(\sum_{T\cap S=\varnothing} p_T)^{k-1}\cdot (1-\sum_{T\cap S=\varnothing} p_T) \\&=(\sum_{T\cup \bar S=\bar S} p_T)^{k-1}\cdot (\sum_{T\cup \bar S=\bar S} p_T) \end{aligned}\)
而 \(\displaystyle \sum_{T\cup S=S} p_T\) 即是对 \(\{p_T\}\) 进行高维前缀和后的结果 \(\{\hat p_T\}\)
因此 \(P(\min(S)=k)=\hat p_{\bar S}^{k-1}\cdot (1-\hat p_{\bar S})\)
\(\begin{aligned} \therefore E(\min(S)=k)&=\sum_{k=1}^{\infty} k\hat p_{\bar S}^{k-1}\cdot (1-\hat p_{\bar S}) \\&=(1-\hat p_{\bar S})\cdot [{\text d\over \text dx}(\sum_{k=1}^\infty x^k)]_{x=1-\hat p_{\bar S}} \\&=(1-\hat p_{\bar S})\cdot [{\text d\over \text dx}({1\over 1-x})]_{x=1-\hat p_{\bar S}} \\&=(1-\hat p_{\bar S})\cdot [{1\over (1-x)^2}]_{x=1-\hat p_{\bar S}} \\&={1\over 1-\hat p_{\bar S}} \end{aligned}\)
跑完 FWT 之后直接按上面公式枚举即可
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef double db;
#define fi first
#define se second
inline int sgn(db x) { return (x>1e-6)-(x<-1e-6); }
template<class T>
void FWT(T *a, int len, int o=1) {
T x, y;
for(int k=0; 1<<k<len; ++k) for(int i=0, j;i<len;++i) if(~i>>k&1) {
j=i^(1<<k);
x=a[i], y=a[i]+a[j];
if(o==-1) y=a[j]-a[i];
a[i]=x, a[j]=y;
}
}
int n;
db p[1<<20];
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n;
for(int i=0;i<1<<n;++i) cin>>p[i];
FWT(p, 1<<n, 1);
bool flag=0;
db res=0;
for(int i=1;i<1<<n;++i)
if( sgn(1-p[i^((1<<n)-1)])==0 ){
flag=1;
break;
}
else if(__builtin_popcount(i)&1) res+=1/(1-p[i^((1<<n)-1)]);
else res-=1/(1-p[i^((1<<n)-1)]);
if(flag) cout<<"INF";
else cout<<fixed<<setprecision(9)<<res;
cout.flush();
return 0;
}