UVA.1639 Candy (期望 高精度)
题意分析
有个人有两个都装着
n
颗糖的箱子,他从其中一个箱子取出一颗糖的概率为
假设
我们首先假设现在另外一个箱子还剩下 i 颗糖果。
分析
既然没有糖了,说明这个人从共取了
∑i=1nCn2∗n−i∗pn+1∗(1−p)n−i∗i
对数优化
由于上式子 pn+1 与 (1−p)n−i 可能非常小,这样的话最后计算会出现问题,所以要想办法进行优化。
优化的办法就是取对数计算。
我们知道: Ckn=n!k!(n−k)! , 两边同时取对数后可以得到:
ln(Ckn)=ln(n!)−ln(k!)−ln((n−k)!)
而 pn+1∗(1−p)n−i 也可以如此计算,从而取对数得到:
(n+1)∗ln(p)+(n−i)∗ln(1−p)
具体看代码
代码总览
#include <bits/stdc++.h>
#define ld long double
#define nmax 2000005
using namespace std;
ld logpre[nmax * 2];
void init(){
for(int i = 1;i<nmax*2;++i){
logpre[i] = logpre[i-1] + log(i);
}
}
ld get(int n, int k){
return logpre[n] - logpre[k] - logpre[n-k];
}
double p;
int n;
int main(){
init();
int kase = 1;
while(scanf("%d %lf",&n,&p) != EOF){
double ans = 0;
long double ans1 = 0,ans2 = 0;
for(int i = 1;i<=n;++i){
ans1 = (get(2*n-i,n) + (n+1) * log(p) + (n-i) * log(1-p));
ans2 = (get(2*n-i,n) + (n+1) * log(1-p) + (n-i) * log(p));
ans += (long double) i* (exp(ans1) + exp(ans2));
}
printf("Case %d: %lf\n",kase++,ans);
}
return 0;
}