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;
}
posted @ 2024-08-14 13:26  yoshinow2001  阅读(7)  评论(0编辑  收藏  举报