Codeforces.24D.Broken robot(期望DP 高斯消元)

时间:2022-11-16 07:50:03

题目链接


Codeforces.24D.Broken robot(期望DP 高斯消元)

可能这儿的会更易懂一些(表示不想再多写了)。

\(f[i][j]\)表示从\((i,j)\)到达最后一行的期望步数。那么有\(f[n][j]=0\)
\(m=1\),答案是\(2(n-x)\)
否则,显然有\[f[i][1]=\frac13(f[i+1][1]+f[i][1]+f[i][2])+1\\f[i][j]=\frac14(f[i+1][j]+f[i][j]+f[i][j-1]+f[i][j+1])+1,\ 1<j<m\\f[i][m]=\frac13(f[i+1][m]+f[i][m]+f[i][m-1])+1\]

别忘了+1→_→
写成矩阵的形式,\[2f[i][1]-f[i][2]=f[i+1][1]+3\\-f[i][j-1]+3f[i][j]-f[i][j+1]=f[i+1][j]+4\\-f[i][m-1]+2f[i][m]=f[i+1][m]+3\]

然后就可以一行一行高斯消元了。
注意到矩阵是个三对角矩阵,我们可以\(O(n)\)完成消元。
具体就是用第\(i\)行的两个变量消掉第\(i+1\)行的第\(i\)个变量,最后到第\(m\)行可以直接算出\(f[i][m]\),代回去。
第一行有\(2f[1]-f[2]=g[1]\),消掉第二行的\(f[1]\)变成\(2.5f[2]-f[3]=g[2]+0.5g[1]\),系数改成\(2\)\(2f[2]-0.8f[3]=0.8(g[2]+0.5g[1])\),重复\(m-2\)次即可。最后会得到\(m-1\)\(2f[i]+a_if[i+1]=b_i\),用第\(m\)行求出\(f[m]\),迭代回去。


//62ms  7700KB
#include <cstdio>
#include <algorithm>
typedef long long LL;
const int N=1005;

double A[N],B[N],f[N][N];

int main()
{
    int n,m,x,y; scanf("%d%d%d%d",&n,&m,&x,&y);
    if(m==1) return printf("%.5f\n",2.0*(n-x)),0;
    for(int i=n-1; i>=x; --i)
    {
        A[1]=-1, B[1]=f[i+1][1]+3;
        for(int j=2; j<m; ++j)
        {
            A[j]=-1, B[j]=4+f[i+1][j]+0.5*B[j-1];
            double t=2/(3+0.5*A[j-1]); A[j]*=t, B[j]*=t;
        }
        B[m]=f[i+1][m]+3+0.5*B[m-1], f[i][m]=B[m]/(2+0.5*A[m-1]);
        for(int j=m-1; j; --j) f[i][j]=(B[j]-f[i][j+1]*A[j])*0.5;
    }
    printf("%.5f\n",f[x][y]);

    return 0;
}