多校賽1010
題意:一場比賽,贏了可以得50分,輸了扣100分,始終用分數低的號比賽。此時把50看成一個單位,已知贏一場比賽的概率爲p求打到20分的場數的期望值。
鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4870點擊打開鏈接
思路:我們用dp[i]表示i到20的期望步數,則狀態轉移方程如下:
q=1-p;
dp[0]=dp[1]*p+dp[0]*q+1;
dp[1]=dp[2]*p+dp[0]*q+1;
dp[2]=dp[3]*p+dp[0]*q+1;
…………
dp[i]=dp[i+1]*p+dp[i-2]*q+1; ---------------1
dp[i+1]=dp[i+2]*p+dp[i-1]*q+1;--------------2
dp[19]=dp[20]*p+dp[17]*q+1;
dp[20]=0;
我們用2式減去1式得到dp[i+1]-dp[i]=(dp[i+2]-dp[i+1])*p+(dp[i-1]-dp[i-2])*q;-------------3
其中dp[i+1]-dp[i]就是步數從i到i+1的期望,令dp[i+1]-dp[i]=t[i],則3式可變成下式
t[i]=t[i+1]*p+t[i-2]*q;
移項得到t[i+1]=(t[i]-t[i-2]*q)/p;這樣的話就可以根據前面得到的結果遞推了。(注意初始化問題)
由於有兩個賬號,統計結果的時候每次加2*t[i];到最後一項的時候只需要加t[i],就可以滿足要求了!代碼如下:
#include<set>
#include<cstdio>
#include<iostream>
using namespace std;
double t[22];
int main()
{
double p;
while(scanf("%lf",&p)!=EOF)
{
double q=1-p;
t[0]=1/p;
t[1]=t[0]/p;
t[2]=t[1]/p;
for(int i=3;i<=19;i++)
t[i]=(t[i-1]-t[i-3]*q)/p;
double res=0;
for(int i=0;i<19;i++)res+=2*t[i];
printf("%.6lf\n",res+t[19]);
}
return 0;
}