hdu4465 2012 Asia Chengdu Regional Contest 概率期望计算+对数放大/缩小幂指数+对数还原

 1 //http://www.cnblogs.com/yefeng1627/archive/2013/04/24/3040112.html
 2 #include<iostream>
 3 #include<cstdlib>//最好开这个库//数学计算交c++更快
 4 #include<stdio.h>
 5 #include<string.h>
 6 #include<math.h>
 7 #define maxn 410000
 8 double F[maxn];
 9 void builtF()
10 {
11     F[1]=0;
12     for(int i=1;i<=maxn;i++)
13     {
14         F[i]=F[i-1]+log((double)i);
15     }
16     return ;
17 }
18 double getC(int n,int m)
19 {
20    // if (m==0) return 1;画蛇添足
21     double ans=F[n]-F[n-m]-F[m];
22     return ans;
23 }
24 using namespace std;
25 int main()
26 {
27     builtF();
28     int n;
29     double p;
30     int cas=0;
31     while(~scanf("%d%lf",&n,&p))
32     {
33         cas++;
34         double p1=log(p);
35         double p2=log(1-p);
36         double ans=0;
37         for(int i=0;i<=n-1;i++)
38         {
39             ans+=(n-i)*((exp(+getC(n+i,i)+(n+1)*p1+i*p2)+exp(+getC(n+i,i)+(n+1)*p2+i*p1)));
40         }
41         printf("Case %d: %.6f\n",cas,ans);
42     }
43     return 0;
44 }
View Code

问题描述:两个盒子,各装n个球,每次打开一个盒子,并拿走一个球,已知每次打开盒子1的概率是p,直到某次打开一个盒子是空的,求另一个盒子剩余的球数的期望。

关键算法:1、概率计算时有个坑,就是空盒子被打开了n+1次,而不是n次。

                  所以答案就是=sum{(n-i)*C(i,n+i)*p^n*(1-p)^i*p} + sum{(n-i)*C(i,n+i)*(1-p)^n*p^i*(1-p)}   0<=i<n, i 表示非空盒中已拿走的球的个数

              2、对数放缩:

              (1)C(m,n)=n!/(m!*(n-m)!) ==>  log(C(m,n))=log(n!)-log(m!)-log((n-m)!) 要知道log(10000!)都是很小的,解决了组合数存储爆long long的问题;

              (2)我们知道p是小于1的小数,那么在p^n,n很大时就会损失精度,double也不可存储,所以我们用 log(p^n)=nlog(p);自然就可存储下来了

              (3)还原时,使用exp(sum)即可,但是要注意,使用cmath库中的数学函数时,用c++提交会大大减少时间,是900ms到200ms的差距啊!!!!

 

 

                                           

posted @ 2013-10-31 13:22  little_w  阅读(356)  评论(0编辑  收藏  举报