zoukankan      html  css  js  c++  java
  • 【BZOJ4036】[HAOI2015] 按位或(Min-Max容斥+FWT)

    点此看题面

    大致题意: 每个单位时间有(p_i)的概率选中(i∈[0,2^n-1]),求期望多少时间后选中的数按位或的结果变成了(2^n-1)

    前言

    典型的数学题:看起来很吓人的知识点+似乎很高深的分析+短短几行的代码。。。

    分析

    要做这道题,首先我们要知道一个叫做(Min-Max)容斥的东西:

    [E(max(S))=sum_{Tsubseteq S}(-1)^{|T|+1}E(min(T)) ]

    具体地,在这题中,(E(min(T)))表示(T)中出现任意一位的期望时间,(E(max(S)))表示(S)中所有位都出现的期望时间(这里的(S)即为(2^n-1))。

    换言之,我们只要能求出(E(min(T))),就可以在(O(2^n))的时间复杂度内通过容斥求出(E(max(S)))。那么我们只需要考虑如何求一个集合中出现任意一位的期望时间。

    首先自然有一个很暴力的式子:

    [E(min(T))=frac1{sum_{i∩T ot=varnothing}p_i} ]

    这个式子的关键是分母中的概率,且这个东西显然不好维护。因此我们反过来考虑:出现任意一位的概率就是(1-)不出现任意一位的概率。

    也即是说:

    [E(min(T))=frac1{1-sum_{i∩T=varnothing}p_i} ]

    (k=T xor (2^n-1))(即(T)的补集),那么这个式子就相当于是:

    [E(min(T))=frac1{1-sum_{isubseteq k}p_i} ]

    显然(sum_{isubseteq k}p_i)可以用(FWT)高效地求出,于是这题就做完了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 20
    #define DB double
    using namespace std;
    int n,s,op[1<<N];DB p[1<<N];
    int main()
    {
    	RI i,g=0;for(scanf("%d",&n),s=1<<n,i=0;i^s;++i) scanf("%lf",p+i);//读入
    	for(i=0;i^s;++i) p[i]&&(g|=i);if(g^(s-1)) return puts("INF"),0;//判无解
    	RI j,k;for(i=1;i^s;i<<=1) for(j=0;j^s;j+=i<<1) for(k=0;k^i;++k) p[i+j+k]+=p[j+k];//FWT
    	DB t=0;for(op[0]=-1,i=0;i^s;++i)//Min-Max容斥
    		op[i]=op[i>>1]*(i&1?-1:1),p[i^(s-1)]<1-1e-8&&(t+=op[i]/(1-p[i^(s-1)]));
    	return printf("%.10lf
    ",t),0;
    }
    
  • 相关阅读:
    C#连接各种数据库的方法
    C#中MDI窗体的一些设置
    Winform子窗体刷新父窗体
    MDI窗体应用程序
    C# 窗体间传值方法大汇总
    mdi父窗体如何向子窗体发送数据
    DataGridView 清空原数据
    js call回调的this指向问题
    sass进阶 @if @else if @else @for循环
    sass的加减乘除
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4036.html
Copyright © 2011-2022 走看看