zoukankan      html  css  js  c++  java
  • P3175 [HAOI2015]按位或(max-min 容斥)

    max-min 容斥:
    (max(S))(S) 中的最大元素,(min(S))(S) 中的最小元素,则有:

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

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

    考虑证明,对于 (S) 中第 (k) 大的数 (x_k) 建立映射 (f(x_k)={1,2cdots k})
    于是对于两数 (a,b),有 (f(max(a,b))=f(a)cup f(b),f(min(a,b))=f(a)cap f(b))
    那么以第一个式子为例

    [|f(max(S))|=|igcup_{x_kin S} f(x_k)|=sum_{Tsubseteq S}(-1)^{|T|-1} |igcap_{x_kin T} f(x_k)|=sum_{Tsubseteq S}(-1)^{|T|-1} |f(min(T))| ]

    由于这显然是个一一映射,所以 (|f(min(T))|) 就可以映射回 (min(T)),于是就证明了这个式子
    这个式子在期望下也成立:

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

    它的变形还可以在第 (k) 大,以及第 (k) 大的期望下成立:

    [operatorname{kthmax}(S)=sum_{Tsubseteq S} (-1)^{|T|-k} binom{|T|-1}{k-1} min(T) ]

    [E(operatorname{kthmax}(S))=sum_{Tsubseteq S} (-1)^{|T|-k} binom{|T|-1}{k-1} E(min(T)) ]

    当然以上对于 (min) 的情况也是同理
    就不证明了


    此题 就用到了在期望下的式子
    (S) 表示 (2^n-1) 每一个二进制位的集合,(max(S)) 表示其中出现最晚的位置的出现时间,(min(S)) 则是出现最早的位置的出现时间
    要求的显然是 (E(max(X)))(X)(n) 个二进制位的全集
    那么由 (E(max(S))=sum_{T subseteq S}(-1)^{|T|-1} E(min(T))),问题就变成了如何求 (E(min(T)))

    对于任意集合 (U,Ucap T eq varnothing),只要 (U) 被加入,(T) 就有了“最早出现的位置”,于是每次取数能出现这样的位置的概率就是所有满足要求的 (U) 的概率和,那么期望就是再取倒数:

    [E(min(T))=frac{1}{sum_{Ucap T eq varnothing} P(U)} ]

    但是这样的 (U) 不太好求,考虑取 (T) 的补集 (G),那么 (U) 显然就是 (G) 的子集,于是用 FWT 的方法求出每个子集和就行了

    #include<cstdio>
    #include<cmath>
    #define reg register
    #define LL_INF (long long)(0x3f3f3f3f3f3f3f3f)
    #define INT_INF (int)(0x3f3f3f3f)
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    #define N 1048588
    int n;
    double p[N];
    int cnt[N];
    inline void FWT(){
    	for(reg int o=2,k=1;o<=n;o<<=1,k<<=1){
    		for(reg int i=0;i<n;i+=o)for(reg int j=0;j<k;j++) p[i+j+k]+=p[i+j];
    	}
    }
    int main(){
    	n=(1<<read());
    	for(reg int i=0;i<n;i++) scanf("%lf",p+i),cnt[i]=cnt[i>>1]+(i&1);
    	FWT();
    	double ans=0;
    	for(reg int i=1;i<n;i++) ans+=((cnt[i]&1)?1:-1)/(1-p[i^(n-1)]);
    	if(ans>1e20) puts("INF");
    	else printf("%lf
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    (转载)Linux系统中分离线程的使用
    (转载)Vim的几种模式介绍
    (转载)Linux下检查内存泄漏、系统性能的系列工具
    (转载)Linux 僵尸进程与孤儿进程
    (转载)valgrind,好东西,一般人我不告诉他~~ 选项
    (转载)Linux进程组、作业、会话的理解
    Open a file, and then readin a file tcl tk
    save vars and arrays
    itcl class example
    constructor with args tcl tk
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/14520247.html
Copyright © 2011-2022 走看看