题解 hdu 4336 Card Collector

传送门


【大意】

\(N\) 种牌,每秒有 \(p_i\) 的概率获得其中的第 \(i\) 张。问所有卡牌都获得的概率。


【分析】

\(\max(S)\) 表示获得集合 \(S\) 的最后一张卡牌时间的随机变量

\(\min(S)\) 表示获得集合 \(S\) 的第一张卡牌时间的随机变量

由扩展 min-max 容斥得 \(\displaystyle E(\text{k-thmax}(S))=\sum_{T\subseteq S}(-1)^{|T|-k}\binom{|T|-1}{k-1}E(\min(S))\)

\(\displaystyle E(\max(S))=\sum_{\varnothing \subset T\subseteq S}(-1)^{|T|-1}E(\min(S))\)

因为 \(\displaystyle P(\min(S)=k)=(\sum_{i\in S}p_i)\cdot (1-\sum_{i\in S}p_i)^{k-1}\)

\(\displaystyle E(\min(S))=\sum_{k=1}^{\infty} k\cdot P(\min(S)=k)\) ,求和得 \(\displaystyle {1\over \sum_{i\in S}p_i}\)


【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef double db;
#define fi first
#define se second

bool eps=1e-6;
inline int sgn(db x) { return (x>eps)-(x<-eps); }

int n;
db p[1<<20];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    while( cin>>n ){
        for(int i=0;i<n;++i) cin>>p[1<<i];
        for(int i=1;i<1<<n;++i) if(i&(i-1))
            p[i]=p[i-(i&-i)]+p[i&-i];

        db res=0;
        for(int i=1;i<1<<n;++i) 
            if(__builtin_popcount(i)&1) res+=1/p[i];
            else res-=1/p[i];
        cout<<fixed<<setprecision(9)<<res<<"\n";
    }
    cout.flush();
    return 0;
}
posted @ 2021-09-02 17:00  JustinRochester  阅读(41)  评论(0编辑  收藏  举报