【HDU4336】Card Collector-Min-Max容斥

测试地址:Card Collector
题目大意: n 张牌,每次有 p i 的概率抽到第 i 张牌,问抽到过所有的牌所需的期望次数。
做法:本题需要用到Min-Max容斥。
很久之前我写过这题的状压DP写法,那个做法时间复杂度为 O ( n 2 n ) ,空间复杂度为 O ( 2 n ) ,而今天本人学会了一种新的做法:Min-Max容斥,这个做法比状压DP更加优美一些。
Min-Max容斥,又称最值反演,是指下面这个式子:
max { S } = T S ( 1 ) | T | + 1 min { T }
其中 S , T 为集合, max { S } , min { S } 表示集合 S 的最大元素和最小元素。先别急着质问这个式子有什么卵用,我们先看看这个式子是怎么来的。
尝试证明右边等于左边。令 x = max { S } ,我们有一个关于集合 T 的映射 f ( T ) ,定义为:若集合 T 中包含 x ,则 f ( T ) 就是 T 去掉 x 后的集合,否则 f ( T ) 就是 T 加上 x 后的集合。显然这个映射有这样一个性质: f ( f ( T ) ) = T ,那么 T f ( T ) 就是一一对应的关系。除去空集和 { x } 两个集合的对应,其它的对应关系中,两个集合的大小正好差 1 ,而它们的最小值都相同,所以根据上面的式子,它们相互抵消。而空集没有最小值,所以整个右边式子的值就等于 { x } 这个集合的贡献: x ,即 max { S }
说了这么多,这个式子在这题中有什么用呢?Min-Max容斥有一个非常重要的推论:
E [ max { S } ] = T S ( 1 ) | T | + 1 E [ min { T } ]
其中 E [ x ] 表示 x 的期望,证明应该显然。而这个式子更常用的意义是这样的:给 S 中每个元素随机赋值,表示这个元素第一次被取到的时间,那么 E [ min { S } ] 的意义就变成 S 中第一个被取的元素的期望被取时间, E [ max { S } ] 的意义就变成 S 中最后一个被取的元素的被取期望时间,也就是 S 中所有元素都被取过所需的期望时间。我们发现这个时间就相当于取的次数,所以也就是期望次数。
这个推论在这题中就非常有用了,因为本题中 E [ min { S } ] = 1 i S p i ,所以我们只需 O ( 2 n ) 枚举集合即可算出 E [ max { S } ] ,空间复杂度也很小( O ( n ) ),可以说是比状压DP优美很多了。
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int n;
double p[25],ans;

void solve(int step,int cnt,double totp)
{
    if (step>n)
    {
        if (!cnt) return;
        double f=(cnt%2)?1.0:-1.0;
        ans+=f/totp;
        return;
    }
    solve(step+1,cnt,totp);
    solve(step+1,cnt+1,totp+p[step]);
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%lf",&p[i]);
        ans=0.0;
        solve(1,0,0.0);
        printf("%.6lf\n",ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/maxwei_wzj/article/details/80762791