题目链接:https://cn.vjudge.net/problem/LightOJ-1408
题目大意:
一个击球手击不中球的概率是 \(p\),当他连续击不中 \(k_1\) 个球或者连续击中 \(k_2\) 个球后停止发球,问发球数的期望是多少。
知识点: 概率与期望
解题思路:
\(dp_{(i,j)}\) 表示连续击中 \(i\) 个球,连续击不中 \(j\) 个球还需要发球的期望数。显然,\(i, j\) 中至少一个为 \(0\),答案即为 \(dp_{(0,0)}\),且 \(dp_{(k_1,0)} = dp_{(0,k_2)} = 0\).
我们有:
\(dp_{(0,j)} = p(dp_{(0,j+1)}+1)+(1-p)(dp_{(1,0)}+1)\)——即连续击不中 \(j\) 个球后,考虑第 \(j+1\) 个球,它有 \(p\) 的概率使得 \(dp_{(0,j)} \rightarrow dp_{(0,j+1)}\),此时发球数的期望即为 \(p(dp_{(0,j+1)}+1)\)(别忘了要在 \(dp_{(0,j+1)}\) 的基础上多发一球);而第 \(j+1\) 个球击中的情况也就不难理解了。
同理得 \(dp_{(i,0)} = (1-p)(dp_{(i+1,0)}+1)+p(dp_{(0,1)}+1)\).
稍微将 \(dp_{(i,0)}\) 代入 \(dp_{(i-1,0)}\),将 \(dp_{(i-1,0)}\) 代入 \(dp_{(i-2,0)}\),我们不难发现(如果还没发现的话,请继续上述操作)如下公式:
\(dp_{(1,0)} = (1-p)dp_{(k_1,0)} + \sum_{t=0}^{k_1-2}(1-p)^t(1+p \cdot dp_{(0,1)}) = \frac{1-(1-p)^{k_1-1}}{p}(1+p \cdot dp_{(0,1)})\).
同理可推出 \(dp_{(0,1)}\) 的公式,由这两条公式可以求出 \(dp_{(1,0)}\) 和 \(dp_{(0,1)}\),再进而求 \(dp_{(0,0)}\).
AC代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 const double ep = 1e-10; 5 int main(){ 6 int T; 7 double p; 8 int k1,k2; 9 scanf("%d",&T); 10 for(int t=1;t<=T;t++){ 11 scanf("%lf%d%d",&p,&k1,&k2); 12 printf("Case %d: ",t); 13 if(p<ep){ 14 printf("%d\n",k1); 15 continue; 16 } 17 if(1.0-p<ep){ 18 printf("%d\n",k2); 19 continue; 20 } //没有这两句也会WA 21 double sum1=(1-pow(1-p,k1-1))/p,sum2=(1-pow(p,k2-1))/(1-p);//此处一定要用等比数列的公式求,直接求加和会WA 22 double dp01,dp10; 23 dp01=(sum2+sum2*(1.0-p)*sum1)/(1.0-sum2*(1.0-p)*sum1*p); 24 dp10=(sum1+sum1*sum2*p)/(1.0-sum1*sum2*p*(1.0-p)); //此处一定要分别推公式求,由dp01求dp10会WA 25 26 printf("%lf\n",(1.0-p)*dp10+p*dp01+1.0); 27 } 28 29 return 0; 30 } 31 //综上可知:破题!!!