HDU 4465 数值计算,避免溢出
数学,数值计算,求期望
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4465
题目描述:
有两个盒子,每个中有n个糖果,(n<10^5)每次任选一个盒子,如果有糖就吃掉,没糖就去开另一个盒子。选中盒子1的概率为p,选中盒子2的概率为1-p.问当发现一个盒子里没有糖时,另一个盒子中糖果的个数的数学期望。
解法:
利用数学期望的定义,结果一共为x = 0,1,2,```,n.如果知道p(x),求sum(x*p(x))即可。为方便计算,设吃掉了i个糖果时发现盒子空。
则有x = 2*n-i时,p[x] = C(i,n)*[p^(n+1)*q^(i-n)+q^(n+1)*p^(i-n)]. n=<i<=2*n. //两个盒子有对称关系
因为n<10^5,计算C(i,n)时会上溢,p^n会下溢。有技巧可解决溢出问题,用公式a = exp(log(a)),log(a*b) = log(a)+log(b),log(a^n) = n*log(a).
再加上公式C(i,n) = i!/(n!*(i-n)!);用s[i]计算出log(i!),用递推式s[i] = s[i-1]+log(i);
代码实现:
for(int i=1; i<N; ++i) s[i] = s[i-1]+log(i);
double ans =0,q = 1-p;//ans 为答案
double logp = log(p);
double logq =log(q);
for(int i=n; i<2*n; ++i)//当i=2*n时,x=0,可不计算
{
double tmp =(2*n-i)*exp(s[i]-s[n]-s[i-n]+(n+1)*logp+(i-n)*logq);
ans += tmp;
tmp =(2*n-i)*exp(s[i]-s[n]-s[i-n]+(n+1)*logq+(i-n)*logp);
ans += tmp;
}