【Learning】min-max容斥以及推广

版权声明:本文为蒟蒻的博主极其水的原创文章,各位大佬转载记得标注id哦。 https://blog.csdn.net/ez_2016gdgzoi471/article/details/81416333

min-max容斥

给定集合S,设max(S)S中的最大值,min(S)S中的最小值,则我们有一个式子:

max(S)=TS(1)|T|1min(T)

这个东西就叫做min-max容斥。
怎么证明?
我们考虑构造一个容斥系数f(x),使得
max(S)=TSf(|T|)min(T)

考虑第x+1大的元素会被统计到的贡献。
则这个贡献为i=0xCxi×f(i+1)
简单来说,就是枚举有哪些集合的最小值会为第x+1大的元素。

[x==0]=i=0xCxi×f(i+1)

二项式反演一下
f(x+1)=i=0x(1)xiCxi[i==0]

得到
f(x+1)=(1)x

因此
f(x)=(1)x1

综上,
max(S)=TSf(|T|)min(T)=TS(1)|T|1min(T)

证明完毕。
下面我们来看几道例题。
由于min-max容斥对于期望同样满足,所以可以很方便地解决一些概率和期望问题。

hdu4336 Card Collector

有n种卡片,每一秒都有Pi的概率获得一张第i种卡片,求每张卡片都至少有一张的期望时间。
我们记max(S)S中最后获得的那种卡片第一次获得的期望时间,min(S)S中的第一个获得的那种卡片第一次获得的期望时间。
仍然满足

max(S)=TS(1)|T|1min(T)


min(T)=1iTPi

直接计算即可。
代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=25;
const double eps=1e-7;
double a[N],ans;
int n;
void dfs(int now,int tot,double sum){
    if(now>n){
        if(sum>eps){
            if(tot&1){
                ans+=1/sum;
            }else{
                ans-=1/sum;
            }
        }
        return;
    }
    dfs(now+1,tot,sum);
    dfs(now+1,tot+1,sum+a[now]);
}
int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++){
            scanf("%lf",&a[i]);
        }
        ans=0;
        dfs(1,0,0);
        printf("%lf\n",ans);
    }
    return 0;
}

bzoj4036 按位或

我们记max(S)S中最后被或到的元素第一次被或到的期望时间,min(S)S中的第一个被或到的元素第一次被或到的期望时间。

max(S)=TS(1)|T|1min(T)


min(S)=1TSPT

我们如果求出了min(s),就直接计算就好了。
怎么求?
TSPT=sumTS=PT=sumT(allS)=(allS)PT

然后FWT计算即可。
代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1050005;
int n,all,tmp,cnt[N];
double sum,res,ans,a[N];
int main(){
    scanf("%d",&n);
    all=1<<n;
    for(int i=0;i<all;i++){
        cnt[i]=cnt[i>>1]+(i&1);
        scanf("%lf",&a[i]);
        sum+=a[i];
        if(fabs(a[i])>1e-6){
            tmp|=i;
        }
    }
    if(tmp!=all-1){
        puts("INF");
        return 0;
    }
    for(int i=1;i<all;i<<=1){
        for(register int j=0;j<all;j+=(i<<1)){
            for(register int k=j;k<j+i;k++){
                a[k+i]+=a[k];
            }
        }
    }
    for(register int i=0;i<all;i++){
        res=sum-a[all-1-i];
        if(res>1e-6){
            res=1/res;
        }else{
            res=0;
        }
        if(cnt[i]&1){
            ans+=res;
        }else{
            ans-=res;
        }
    }
    printf("%.8lf\n",ans);
    return 0;
}

推广 kth min-max容斥

我们考虑构造一个容斥系数f(x),使得

kthmax(S)=TSf(|T|)min(T)

考虑第x+1大的元素会被统计到的贡献。
这个贡献为i=0xCxi×f(i+1)

[x==k1]=i=0xCxi×f(i+1)

二项式反演一下
f(x+1)=i=0x(1)xiCxi[i==k1]

得到
f(x+1)=(1)(x(k1))Cxk1

因此
f(x)=(1)xkCx1k1

综上,
kthmax(S)=TSf(|T|)min(T)=TS(1)|T|kC|T|1k1min(T)

有一道例题,还没弄懂,不会做:重返现世
这道题是ypl学长的神题QwQ

没有更多推荐了,返回首页