uva 1639 Candy (对数处理精度)

https://vjudge.net/problem/UVA-1639

 

有两个盒子各有n(n≤2*10 5 )个糖,每天随机选一个(概率分别为p,1-p),然后吃一颗糖。

直到有一天,打开盒子一看,没糖了!

输入n, p,求此时另一个盒子里糖的个数的数学期望。

 

若最后打开第1个盒子,此时第2个盒子有i颗,则这之前打开过n+(n-i)次盒子,

其中有n次取的是盒子1,其余n-i次取的盒子2,

概率为C(2n-i, n)*p^(n+1) *(1-p)^(n-i)

注意p的指数是n+1,因为除了前面打开过n次盒子1之外,最后又打开了一次。

同理,若最后打开第2个盒子,此时第1个盒子有i颗,

概率为 C(2n-i, n)*(1-p)^(n+1) * p^(n-i)

所以ans=

Σ i*C(2n-i, n)*p^(n+1) *(1-p)^(n-i)

+

Σ i*C(2n-i, n)*(1-p)^(n+1) * p^(n-i)

 

 

精度处理:转化为对数v

设v1(i) = ln(C(2n-i, n)) + (n+1)ln(p) +(n-i)ln(1-p),

v2(i) = ln(C(2n-i, n)) + (n+1)ln(1-p) +(n-i)ln(p)

最终答案为 Σ{ i*(e^v1(i) +e^v2(i) ) }

 

 

#include<cmath>
#include<cstdio>
#define N 200001
using namespace std;
long double logsum[N*2];
int main()
{
    for(int i=1;i<N*2;i++) logsum[i]=logsum[i-1]+log((long double)i);
    int n,t=0; 
    double p,ans;
    while(scanf("%d",&n)!=EOF)
    {
        scanf("%lf",&p);
        ans=0.0; 
        long double tmp1=(n+1)*log(p),tmp2=(n+1)*log(1-p);
        long double logp=log(p),logpp=log(1-p);
        for(int i=1;i<=n;i++)
        {
            long double k=logsum[2*n-i]-logsum[n]-logsum[2*n-i-n];
            ans+=(i*(exp(k+tmp1+(n-i)*logpp)+exp(k+tmp2+(n-i)*logp)));
        }
        t++;
        printf("Case %d: %.6f\n",t,ans);
    }
}

 

posted @ 2017-06-04 14:41  TRTTG  阅读(395)  评论(0编辑  收藏  举报