CF24D Broken robot

不想打式子了,就抄别人的式子吧(毫无版权意识...)

首先可以列出dp方程,然后可以发现他有后效性

 

可以把各状态看成未知量,状态转移看做方程,由于全为一次方程,所以可以用高斯消元求解

而本题使用倒推更为方便,可以将行作为阶段,倒序递推

如果直接高斯消元复杂度是$O(n^4)$

然后注意到每个方程只有极少的非零系数,且排列有规律

如:

所以我们可以快速消元

$code:$

#include<bits/stdc++.h>
using namespace std;
const int N=1007;
int n,m,x,y;
double f[N],a[N][N],b[N];
void build(){
    a[1][1]=2.0/3.0;
    a[m][m]=2.0/3.0;
    a[1][2]=-1.0/3.0;
    a[m][m-1]=-1.0/3.0;
    for(int i=2;i<=m-1;i++){
        a[i][i]=3.0/4.0;
        a[i][i-1]=-1.0/4.0;
        a[i][i+1]=-1.0/4.0;
    }
}
void gauss(){
    for(int i=1;i<=m;i++){
        double rate=a[i+1][i]/a[i][i];
        a[i+1][i]-=rate*a[i][i];
        a[i+1][i+1]-=rate*a[i][i+1];
        b[i+1]-=rate*b[i];
    }
    f[m]=b[m]/a[m][m];  
    for(int i=m-1;i>0;i--){
        f[i]=(b[i]-f[i+1]*a[i][i+1])/a[i][i];
    }
}
int main(){
    cin>>n>>m>>x>>y;
    if(m==1){
        printf("%.8lf\n",(double)2.0*(n-x));
        return 0;
    }
    for(int i=n-1;i>=x;i--){
        b[1]=f[1]/3.0+1.0;
        b[m]=f[m]/3.0+1.0;
        for(int j=2;j<m;j++){
            b[j]=f[j]/4+1.0;
        }
        build();
        gauss();
    }
    printf("%.8lf\n",f[y]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Hikigaya/p/11422729.html
今日推荐