/*
translation:
两个盒子各有n个糖果,每天随机选一个盒子(概率为p,1-p)并且吃掉里面的一颗糖果。
知道有一天打开盒子时发现是空的,求此时另外一个盒子里面糖果的个数的数学期望?
solution:
数学期望,利用对数减少浮点类型数据的精度损失方法。
假设另外第二个个盒子里面剩下了i颗,则概率为C(2n-i,n)*p^n*(1-p)^(n-i)
同理,如果是地一个盒子里面剩下了i,则概率为C(2n-i,n)*(1-p)^n*p^(n-i)
如此利用定理就能够算出答案了。
但是计算的时候有一个问题,那就是p的那么多阶的次方造成的后果就是会损失很多的精度,所以可以
利用对数的性质来将乘法操作转变为加法操作。即可减少精度的损失。
note:
1:当浮点数据类型接近0的时候,乘法操作很可能导致精度损失,利用对数的性质将乘法操作转换为加法操作即可
减少精度的损失!
date:2016.10.8
*/
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 200000 + 5;
typedef long double ld;
ld logFac[maxn*2]; //logFac[i]表示i!(自然数e为底)
int n; double p;
void initTable() {
logFac[0] = 0;
for(int i = 1; i <= maxn; i++) logFac[i] = logFac[i-1] + log(i);
}
ld countC(int a, int b) {
return (ld)(logFac[a] - logFac[b] - logFac[a-b]);
}
int main() {
//freopen("in.txt", "r", stdin);
initTable(); //计算n!对数的值
int kase = 0;
while(~scanf("%d%lf", &n, &p)) {
ld ans = 0.0;
for(int i = 0; i <= n; i++) { //剩余i个棋子
ld c = countC(2*n - i, n);
ld v1 = c + (n+1)*log(p) + (n-i)*log(1-p);
ld v2 = c + (n+1)*log(1-p) + (n-i)*log(p);
ans += (ld)i * (exp(v1) + exp(v2));
}
printf("Case %d: %.6llf\n", ++kase, ans);
}
}
uva1639(数学期望,利用对数减少浮点类型数据的精度损失方法)
最新推荐文章于 2020-11-10 21:27:41 发布