• [HAOI2015]按位或(min-max容斥,FWT,FMT)


    题目链接:洛谷

    题目大意:给定正整数 $n$。一开始有一个数字 $0$,然后每一秒,都有 $p_i$ 的概率获得 $i$ 这个数 $(0le i< 2^n)$。一秒恰好会获得一个数。每获得一个数,就要将我们有的数与获得的数进行按位或。问期望经过多少秒后,我们的数变成 $2^n-1$。

    $1le nle 20,sum p_i=1$。


    %%%stO shadowice1984 Orz%%%

    首先定义 $min(S)$ 表示 $S$ 中第一个变为 $1$ 的元素的时间。(其中 $S$ 是一个二进制数,是 $1$ 的位表示这一位计入答案)

    $max(S)$ 表示最后一个变为 $1$ 的元素的时间。这也符合 $min$ 和 $max$ 的定义。

    (以下定义全集 $U=2^n-1$)

    我们要求的就是 $E(max(U))$。

    容斥:$E(max(U))=sumlimits_{S eqvarnothing}(-1)^{|S|+1}E(min(S))$

    现在问题就是求 $E(min(S))$,就是有元素变为 $1$。

    套期望的公式:$E(min(S))=sumlimits^{+infty}_{i=1}iP(min(S)=i)$

    $P(min(S)=i)$ 表示恰好在第 $i$ 秒出现 $1$ 的概率。

    前 $i-1$ 秒都没有出现,所以应该是 $sumlimits_{Tcap S=varnothing}P(T)$。其中 $P(T)$ 表示出现的数是 $T$ 的概率。

    第 $i$ 秒有出现,所以应该是 $1-sumlimits_{Tcap S=varnothing}P(T)$。

    乘法原理,$P(min(S)=i)=(sumlimits_{Tcap S=varnothing}P(T))^{i-1}(1-sumlimits_{Tcap S=varnothing}P(T))$

    那么经过一通爆算,$E(min(S))=dfrac{1}{1-sumlimits_{Tcap S=varnothing}P(T)}$。

    转换一下:$E(min(S))=dfrac{1}{1-sumlimits_{Tsubseteqcomplement_US}P(T)}$。

    现在最严峻的问题就是计算每个集合的子集和。

    最裸的枚举,$O(4^n)$。

    技巧一点的枚举,$O(3^n)$。

    那么就要说到一个很有趣的事情了,我也是做了这题才知道的……

    回想一下FWT(或者FMT)做按位或卷积的时候:

    $C_i=sumlimits_{j|k=i}A_jB_k$

    令 $widehat{C}_i=sumlimits_{jsubseteq i}C_j$

    那么就有 $widehat{C}_i=sumlimits_{j|ksubseteq i}A_jB_k$

    也就是 $widehat{C}_i=sumlimits_{jsubseteq i,ksubseteq i}A_jB_k$

    也就是 $widehat{C}_i=widehat{A}_iwidehat{B}_i$!

    于是需要一种从 $A$ 到 $widehat{A}$ 的变换还有它的逆变换。

    于是就有了FWT(或者FMT)……

    (所以说,FWT比FFT要好理解,那就要理解啊)

    那么我们就知道了,FWT的或变换一次后新的序列就是原序列的子集和形式!

    好的,时间复杂度 $O(n2^n)$。

    代码:(实际上特别好写)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1111111;
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline int read(){
        char ch=getchar();int x=0,f=0;
        while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return f?-x:x;
    }
    int n,cnt[maxn];
    double p[maxn];
    void FWTor(double *A){
        for(int i=1;i<1<<n;i<<=1)
            for(int j=0,r=i<<1;j<1<<n;j+=r)
                FOR(k,0,i-1) A[i+j+k]+=A[j+k];
    }
    int main(){
        n=read();
        FOR(i,0,(1<<n)-1) scanf("%lf",p+i);
        FWTor(p);
        FOR(i,1,(1<<n)-1) cnt[i]=cnt[i>>1]+(i&1);
        double ans=0;
        FOR(i,1,(1<<n)-1){
            if(1-p[((1<<n)-1)^i]<1e-8) return puts("INF"),0;
            ans+=1/(1-p[((1<<n)-1)^i])*(cnt[i]&1?1:-1);
        }
        printf("%.10lf
    ",ans);
    }
    View Code
  • 相关阅读:
    P4178 Tree
    CF437D The Child and Zoo
    CF1032G Chattering ST表+倍增
    P4165 [SCOI2007]组队 推柿子+差分
    P1450 [HAOI2008]硬币购物 容斥原理+完全背包
    P6275 [USACO20OPEN]Sprinklers 2: Return of the Alfalfa P 轮廓线DP
    P6009 [USACO20JAN]Non-Decreasing Subsequences P 矩阵优化DP
    P2605 [ZJOI2010]基站选址 线段树优化DP
    P5597 【XR-4】复读 思维题 +二叉树合并
    P5304 [GXOI/GZOI2019]旅行者 最短路+位运算优化
  • 原文地址:https://www.cnblogs.com/1000Suns/p/10388001.html
Copyright © 2020-2023  润新知