hdu 4465 Candy 数学期望 负二项分布与 数值计算技巧
首先是对于概率的计算,负二项分布:
物品A取与不取概率为,p,1-p, 共取 k+r次,最后一次取A ,且取A总次数为 r 次概率为:
则这里两个盒子取也可转换成此模型, 则期望公式为:
然后是公式的计算, 这里有两个问题.
1. 组合数 \binom{ 2n }{ n } 太大,会上溢
2. p^n 太小会下溢.
对于问题一:
排列过大,考虑到 y = logx 函数, log(n!) 也不会很大. 又
令 f(x) = log( x! ),则有
预处理出 函数f() 就可以 O(1)求出 log( \binom{n}{m} )了. 然后 再求个 exp( x ) 就可以还原了.
对于问题二:
p^x 值过小. log( p^x ) = x * logp 这样值就在可控范围内. 同样一次 exp( x ) 就可以还原
View Code
#include<cstdio> #include<cstdlib> #include<cmath> const int N = (int)5e5+10; int n; double p, f[N]; double C(int n, int m){ return f[n] - f[m] - f[n-m]; } int main(){ int Case = 1; f[0] = 0; for(int i = 1; i <= 400000; i++) f[i] = f[i-1]+log(1.*i); while( scanf("%d %lf", &n,&p) != EOF){ double res = 0; double p1 = log(p), p2 = log(1-p); for(int i = 0; i <= n; i++){ // res += 1.*i*c[n+n-i]*(p1[n+1]*p2[n-i]+p1[n-i]*p2[n+1]); res += 1.*i*( exp(C(n+n-i,n) + (n+1)*p1 + (n-i)*p2 ) +exp( C(n+n-i,n) + (n+1)*p2 + (n-i)*p1 ) ); } printf("Case %d: %.6f\n", Case++, res ); } return 0; }