Candy UVA 1639 (数学期望)
有两个盒子各有n颗糖(n<=2*105),从两个盒子取糖的概率为p和1-p,直到一个盒子没糖,求另一个盒子中糖的个数的数学期望。
期望公式为:
E
=
∑
i
=
1
n
i
∗
E
(
i
)
=
∑
j
=
0
n
(
n
−
j
)
∗
C
n
+
j
j
[
p
n
+
1
∗
(
1
−
p
)
j
+
(
1
−
p
)
n
+
1
∗
p
j
]
E=\sum_{i=1}^{n}i*E(i)=\sum_{j=0}^{n}(n-j)*C_{n+j}^{j}[p^{n+1}*(1-p)^{j}+(1-p)^{n+1}*p^{j}]
E=i=1∑ni∗E(i)=j=0∑n(n−j)∗Cn+jj[pn+1∗(1−p)j+(1−p)n+1∗pj]
假设最终看到盒子1没糖,那么盒子1刚好被选中n+1次(包括最后一次被选到)。那么从盒子2拿出糖的个数设为j,所以此时另一个盒子的糖的个数为n-j。整个过程中作出选择的次数为n+j+1,由于最后一次选择必为盒子1,所以只能在前n+j次选择盒子2,选择了j次(拿走了j颗糖),所以有C(n+j,j)种情况。
同理于对于最终看到盒子2没糖的情况。
由于n最高可达2*105,组合数最高可达C(2n,n),而且p的n次幂会非常趋近于0,如果直接相乘会造成较大的精度损失。这种情况可以用对数处理。
C n + j j ∗ p n + 1 ∗ ( 1 − p ) j = e ln ( C n + j j ∗ p n + 1 ∗ ( 1 − p ) j ) = e ln C n + j j + ( n + 1 ) ∗ ln p + j ∗ ln ( 1 − p ) C_{n+j}^j*p^{n+1}*(1-p)^j =e^{\ln_{}{(C_{n+j}^j*p^{n+1}*(1-p)^j)}} =e^{\ln_{}{C_{n+j}^j}+(n+1)*\ln_{}{p}+j*\ln_{}{(1-p)}} Cn+jj∗pn+1∗(1−p)j=eln(Cn+jj∗pn+1∗(1−p)j)=elnCn+jj+(n+1)∗lnp+j∗ln(1−p)
且
C
n
+
j
+
1
j
+
1
=
C
n
+
j
j
∗
(
n
+
j
+
1
)
j
+
1
C_{n+j+1}^{j+1}=C_{n+j}^{j}*\frac{(n+j+1)}{j+1}
Cn+j+1j+1=Cn+jj∗j+1(n+j+1)
ln
C
n
+
j
+
1
j
+
1
=
ln
C
n
+
j
j
+
ln
(
n
+
j
+
1
)
−
ln
(
j
+
1
)
\ln_{}{C_{n+j+1}^{j+1}}=\ln{}{C_{n+j}^{j}}+\ln{(n+j+1)}-\ln{(j+1)}
lnCn+j+1j+1=lnCn+jj+ln(n+j+1)−ln(j+1)
可以先计算指数部分。
E
(
n
−
j
)
=
(
n
−
j
)
∗
[
e
ln
C
n
+
j
j
+
(
n
+
1
)
∗
ln
p
+
j
∗
ln
(
1
−
p
)
+
e
ln
C
n
+
j
j
+
(
n
+
1
)
∗
ln
(
1
−
p
)
+
j
∗
ln
p
]
E(n-j)=(n-j)*[e^{\ln_{}{C_{n+j}^j}+(n+1)*\ln_{}{p}+j*\ln_{}{(1-p)}}+e^{\ln_{}{C_{n+j}^j}+(n+1)*\ln_{}{(1-p)}+j*\ln_{}{p}}]
E(n−j)=(n−j)∗[elnCn+jj+(n+1)∗lnp+j∗ln(1−p)+elnCn+jj+(n+1)∗ln(1−p)+j∗lnp]
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main(void)
{
// freopen("out.txt","w",stdout);
int n;
long double p;
int t=1;
while(cin>>n>>p)
{
long double lgp=log(p);
long double lgp1=log(1-p);
long double lgpn=(n+1)*lgp;
long double lgp1n=(n+1)*lgp1;
long double lgc=log(1);
long double ans1=lgc+lgpn;
long double ans2=lgc+lgp1n;
long double ans=(long double)n*(exp(ans1)+exp(ans2));
for(int j=1;j<n;j++)
{
lgc+=log(n+j)-log(j);
ans1=lgc+lgpn+j*lgp1;
ans2=lgc+lgp1n+j*lgp;
ans+=(long double)(n-j)*(exp(ans1)+exp(ans2));
}
printf("Case %d: %.6Lf\n",t++,ans);
}
// fclose(stdout);
}
//10 0.400000
//100 0.500000
//124 0.432650
//325 0.325100
//532 0.487520
//2276 0.720000