POJ3682 King Arthur’s Birthday Celebration
题目链接:[http://poj.org/problem?id=3682]
题目大意:
有一枚硬币抛到正面的概率为 p,每天抛一次,每抛一次要比上一次多消耗 2 MP,要求输出(ans1)抛到 k 次正面的期望天数和(ans2)消耗的 MP 值的期望。
题目分析:
关于期望的题,就是找到递推关系然后DP或者直接找到公式求解。
对于ans1,因为每次抛硬币是独立的事件,与前后都没有影响。每天都有 p 的概率抛到正面,如果只要求抛到一次,那么设期望的天数为X,则p * X = 1 ==> X = 1 / p,推广到多次的情况下则可以得到:ans1 = X * k = 1/p * k = k/p。
对于ans2,可以找出递推关系,再通过递推关系推出公式,对于第 k 次抛到正面需要消耗的MP,存在两种情况:
- 抛到正面,概率为p 这种情况下不需要消耗MP
- 抛到反面,概率为1-p 这种情况下需要消耗此时期望天数对应的MP
得到递推公式:
F
[
k
]
=
p
⋅
F
[
k
−
1
]
+
(
1
−
p
)
⋅
F
[
k
]
+
2
⋅
k
p
−
1
F[ k ] = p\cdot F[k-1]+(1-p)\cdot F[k]+2\cdot \frac{k}{p}-1
F[k]=p⋅F[k−1]+(1−p)⋅F[k]+2⋅pk−1
将递推公式化简:
p
⋅
F
[
k
]
=
p
⋅
F
[
k
−
1
]
+
2
⋅
k
p
−
1
p\cdot F[k] = p\cdot F[k-1]+2\cdot \frac{k}{p}-1
p⋅F[k]=p⋅F[k−1]+2⋅pk−1
F
[
k
]
=
F
[
k
−
1
]
+
2
⋅
k
p
2
−
1
p
F[k]=F[k-1]+2\cdot\frac{k}{p^2}-\frac{1}{p}
F[k]=F[k−1]+2⋅p2k−p1
F
[
k
−
1
]
=
F
[
k
−
2
]
+
2
⋅
k
−
1
p
2
−
1
p
F[k-1]=F[k-2]+2\cdot\frac{k-1}{p^2}-\frac{1}{p}
F[k−1]=F[k−2]+2⋅p2k−1−p1
⋯
⋯
\cdots \cdots
⋯⋯
F
[
2
]
=
F
[
1
]
+
2
⋅
2
p
2
−
1
p
F[2]=F[1]+2\cdot\frac{2}{p^2}-\frac{1}{p}
F[2]=F[1]+2⋅p22−p1
F
[
1
]
=
F
[
0
]
+
2
⋅
1
p
2
−
1
p
F[1]=F[0]+2\cdot\frac{1}{p^2}-\frac{1}{p}
F[1]=F[0]+2⋅p21−p1
累
加
得
到
:
F
[
k
]
=
F
[
0
]
+
2
p
2
∑
n
=
1
k
n
−
k
p
,
其
中
F
[
0
]
=
0
累加得到:F[k]=F[0]+\frac{2}{p^2}\sum _{n=1}^{k}n-\frac{k}{p}\ \ \ \ \ ,其中F[0] = 0
累加得到:F[k]=F[0]+p22n=1∑kn−pk ,其中F[0]=0
化
简
之
后
得
到
:
F
[
k
]
=
k
+
k
2
−
k
p
p
2
化简之后得到:F[k]=\frac{k+k^2-kp}{p^2}
化简之后得到:F[k]=p2k+k2−kp
AC代码1:
#include<cstdio>
#include<cstring>
using namespace std;
static const int maxn = 1111;
int k;
double p,DP[maxn];
int main(){
while(scanf("%d",&k) && k){
scanf("%lf",&p);
DP[0] = 0;
for(int i=1;i<=k;i++)
DP[i] = DP[i-1]+2*i/(p*p)-1/p;
printf("%.3f %.3f\n",k/p,DP[k]);
}
return 0;
}
AC代码2:
#include<cstdio>
using namespace std;
int k;
double p;
int main(){
while(scanf("%d",&k) && k){
scanf("%lf",&p);
printf("%.3f %.3f\n",k/p,(k+k*k-k*p)/(p*p));
}
return 0;
}