HAOI2015按位或-FWT、min-max容斥
link:https://www.luogu.com.cn/problem/P3175
刚开始你有一个数字 \(0\),每一秒钟你会随机选择一个 \([0,2^n-1]\) 的数字,与你手上的数字进行 或 操作。选择数字 \(i\) 的概率是 \(p_i\)。保证 \(0\leq p_i \leq 1\),\(\sum p_i=1\) 。问期望多少秒后,你手上的数字变成 \(2^n-1\)。
\(1\leq n\leq 21\)
一开始是 \(0\) 要每位变成 \(1\),对每个数位集合考虑,相当于求 \(\max S=\sum_{T}(-1)^{|T|+1} \min( T)\) ,对 \(\min T\) 则是说子集内有一个数变成 \(1\) 就行,反过来算都变不了 \(1\) 的概率= \(\sum_{j\subset T^c }p_j\),则这部分的期望次数是 $$\min T=\frac{1}{1-\sum_{j\subset T^c }p_j}$$
\(j\subset T^c\) 等于在说 \(j\cup T_c= T_c\) ,就是OR卷积的形式:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=21;
const double eps=1e-9;
int n,mx;
double f[1<<N];
int main(){
fastio;
cin>>n;mx=(1<<n);
rep(i,0,mx-1)cin>>f[i];
for(int x=2;x<=mx;x<<=1){
int k=x>>1;
for(int i=0;i<mx;i+=x)for(int j=0;j<k;j++)f[i+j+k]+=f[i+j];
}
double ans=0;
bool bad=false;
rep(S,1,mx-1){
int C=((mx-1)^S);
if(fabs(f[C]-1)<eps){
bad=true;
break;
}
if(__popcount(S)&1)ans+=1/(1-f[C]);
else ans-=1/(1-f[C]);
}
if(!bad)cout<<fixed<<setprecision(8)<<ans;
else cout<<"INF";
return 0;
}