Candy UVA - 1639

本秂侑毒 提交于 2020-02-12 04:26:55

问题

分析

设被取完的是第一个盒子,最后打开的是第一个盒子,同时第二个盒子发现有i颗,所以一共拿了n+n-i颗糖,概率是(C(2ni,n)pn(1p)ni)p(C(2n-i,n)p^{n}(1-p)^{n-i})*p,最后一个p代表最后一次打开的是第一个盒子,发现为空
因为n最大时21052*10^5,那么(C(2ni,n)(C(2n-i,n)会很大pn(1p)ni)pp^{n}(1-p)^{n-i})*p接近0,同时,为了防止损失精度,采用对数,所以最后打开的是第一个盒子,第二个盒子剩余i个概率是ev1(i),e^{v1(i)},v1(i)=ln(C(2ni,n))+(n+1)ln(p)+(ni)ln(1p)v1(i)=ln(C(2n-i,n))+(n+1)ln(p)+(n-i)ln(1-p)
最后打开的是第二个盒子,第一个盒子剩余i个概率是ev2(i),e^{v2(i)},v2(i)=ln(C(2ni,n))+(n+1)ln(1p)+(ni)ln(p)v2(i)=ln(C(2n-i,n))+(n+1)ln(1-p)+(n-i)ln(p)
总的期望是i=0N(ev1(i)+ev2(i))i\sum_{i=0}^N(e^{v1(i)}+e^{v2(i)})*i

要使用long double确保精度
参考:https://www.cnblogs.com/dwtfukgv/p/5538719.html

#include <cstring>
#include <cstdio>
#include <vector>
#include <iostream>
#include <cmath>
#include <vector>
#include <utility>
using namespace std;
typedef long double ld;
const int maxn=400010;
long double ln_ld[maxn];  //ln_ld[i]存储ln(i!)的值
int n,kase=0;
double p;
void init(){
    ln_ld[1]=0;  //ln(1)=0
    for(int i=2;i<maxn;++i){
        ln_ld[i]=ln_ld[i-1]+log(i);
    }
}

int main(void){
    init();
    while(scanf("%d%lf",&n,&p)!=EOF){
        long double ans=0;
        for(int i=1;i<=n;++i){
            long double c=ln_ld[2*n-i]-ln_ld[n]-ln_ld[n-i]; //ln(C(2n-i,n))
            long double v=exp(c+(n+1)*log(p)+(n-i)*log(1-p))+exp(c+(n+1)*log(1-p)+(n-i)*log(p));
            ans+=i*v;
        }
        printf("Case %d: %.6lf\n",++kase,(double)ans);
    }
    return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!