https://vjudge.net/problem/UVA-1639
有两个盒子各有n(n≤2*10 5 )个糖,每天随机选一个(概率分别为p,1-p),然后吃一颗糖。
直到有一天,打开盒子一看,没糖了!
输入n, p,求此时另一个盒子里糖的个数的数学期望。
若最后打开第1个盒子,此时第2个盒子有i颗,则这之前打开过n+(n-i)次盒子,
其中有n次取的是盒子1,其余n-i次取的盒子2,
概率为C(2n-i, n)*p^(n+1) *(1-p)^(n-i)
注意p的指数是n+1,因为除了前面打开过n次盒子1之外,最后又打开了一次。
同理,若最后打开第2个盒子,此时第1个盒子有i颗,
概率为 C(2n-i, n)*(1-p)^(n+1) * p^(n-i)
所以ans=
Σ i*C(2n-i, n)*p^(n+1) *(1-p)^(n-i)
+
Σ i*C(2n-i, n)*(1-p)^(n+1) * p^(n-i)
精度处理:转化为对数v
设v1(i) = ln(C(2n-i, n)) + (n+1)ln(p) +(n-i)ln(1-p),
v2(i) = ln(C(2n-i, n)) + (n+1)ln(1-p) +(n-i)ln(p)
最终答案为 Σ{ i*(e^v1(i) +e^v2(i) ) }
#include<cmath> #include<cstdio> #define N 200001 using namespace std; long double logsum[N*2]; int main() { for(int i=1;i<N*2;i++) logsum[i]=logsum[i-1]+log((long double)i); int n,t=0; double p,ans; while(scanf("%d",&n)!=EOF) { scanf("%lf",&p); ans=0.0; long double tmp1=(n+1)*log(p),tmp2=(n+1)*log(1-p); long double logp=log(p),logpp=log(1-p); for(int i=1;i<=n;i++) { long double k=logsum[2*n-i]-logsum[n]-logsum[2*n-i-n]; ans+=(i*(exp(k+tmp1+(n-i)*logpp)+exp(k+tmp2+(n-i)*logp))); } t++; printf("Case %d: %.6f ",t,ans); } }