官方题解:
令(x, y)表示高分为x,低分为y的状态(x >= y),E(x, y)表示从(x, y)到达(1000, ?)的比赛场数期望。容易得到E(x, y) = P * E(x1, y1) + (1 - P) * E(x2, y2) + 1,其中,(x1, y1)表示rating上升后的状态,(x2, y2)表示rating下降后的状态。每50分一个状态,共有210个状态(21*20/2)。
移项后得E(x, y) -P * E(x1, y1) - (1 - P) * E(x2, y2) = 1,共有210个这样的方程组。高斯消元求解,x[0]代表E(0,0)这个状态到目标状态的期望。
注意精度。
这个题也可以dp做,递推公式跟上面差不多
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=220;
const double eps=1e-9;
int id[30][30];
double x[maxn],a[maxn][maxn];
int equ,var;
double P;
void Gauss()
{
int row=0,col=0;
for(;row<equ&&col<var;col++,row++)
{
int r=row;
for(int i=row+1;i<equ;i++)
if(fabs(a[i][col])>fabs(a[r][col]))r=i;
if(row!=r)
for(int i=0;i<=var;i++)swap(a[r][i],a[row][i]);
for(int i=row+1;i<equ;i++)
{
for(int j=var;j>=col;j--)
a[i][j]-=a[i][col]/a[row][col]*a[row][j];
}
// for(int i=row+1;i<equ;i++)
// {
// double f=a[i][col]/a[row][col];
// for(int j=col;j<=var;j++)
// a[i][j]-=f*a[row][j];
// }
}
for(int i=equ-1;i>=0;i--)
{
for(int j=i+1;j<var;j++)
a[i][var]-=a[i][j]*a[j][var];
a[i][var]/=a[i][i];
}
}
void init()
{
memset(a,0,sizeof(a));
equ=var=210;
for(int i=0;i<20;i++)
{
for(int j=0;j<=i;j++)
{
int t=id[i][j];
a[t][t]=1;
a[t][var]=1;
int m=id[i][max(0,j-2)];
a[t][m]-=(1-P);
if(j<i)m=id[i][j+1];
else if(j==i)m=id[i+1][j];
a[t][m]-=P;
}
}
}
int main()
{
int cnt=0;
memset(id,-1,sizeof(id));
for(int i=0;i<20;i++)
for(int j=0;j<=i;j++)id[i][j]=cnt++;
while(scanf("%lf",&P)!=EOF)
{
memset(a,0,sizeof(a));
init();
Gauss();
printf("%.6lf\n",a[0][var]);
}
return 0;
}