题解 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;
}
posted @ 2021-09-02 16:29  JustinRochester  阅读(45)  评论(0编辑  收藏  举报