【DP】AcWing 290. 坏掉的机器人

分析

这题不如说是一道数学题吧 hh。

考虑倒推,假设现在已经求出了第 \(i+1\) 行的结果 \(c\),现在求第 \(i\) 行的结果,记为 \(y\)​,那么递推式为:

\[\begin{aligned} \frac{2}{3} y_1 - \frac{1}{3}y_2 = \frac{1}{3}c_1 + 1 \\ \frac{2}{3} y_m - \frac{1}{3}y_{m-1} = \frac{1}{3}c_m + 1 \\ -\frac{1}{4} y_m + \frac{3}{4}y_{m-1} - \frac{1}{4}y_{m+1} = \frac{1}{4}c_j + 1 &&& j\in[2,m-1] \end{aligned} \]

递推的边界是第 \(n\) 行,此时的 \(c\) 值都是 \(0\)

写成 \(m\times m\) 的矩阵就是(以 \(m=3\) 为例):

\[\begin{pmatrix} \frac{2}{3} & -\frac{1}{3} & 0 \\ -\frac{1}{4} & \frac{3}{4} & -\frac{1}{4} \\ 0 & -\frac{1}{3} & \frac{2}{3} \\ \end{pmatrix} \begin{pmatrix} y_1 \\ y_2 \\ y_3 \end{pmatrix} = \begin{pmatrix} \frac{1}{3} c_1 + 1 \\ \frac{1}{4} c_2 + 1 \\ \frac{1}{3} c_3 + 1 \end{pmatrix} \]

那么进行高斯消元并求出 \(y\) 即可。

当然,因为这个矩阵比较特殊,我们不需要而且也不能直接用普通的高斯消元(复杂度 \(O(n^3)\)),注意到这个矩阵化成上三角矩阵的代价只需要 \(O(n)\),类似地,化为对角矩阵的代价也是 \(O(n)\),所以整个过程 \(O(n)\) 即可完成。

这题有一个边界问题:\(m=1\) 的情况,上面的递推式显然不正确,在原做法上修改过于复杂,所以我们将其作为一个小问题解决:

给你一个数轴,从 \(0\) 出发,问到点 \(i\) 的期望步数是多少?

那么我们有 \(y_i = \frac{1}{2}(y_i + y_{i-1}) + 1\),化简得 \(y_i = y_{i-1} + 2\),首项自然是 \(0\),故通项公式为 \(y_i = 2i\)。​

实现

主体部分 30 行,很短的 qwq~。

// Problem: 坏掉的机器人
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/292/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)

const int N=1010;

int n, m;
int tx, ty;
double y[N], c[N];

double w[N][N];
void get(){
	rep(j,1,m){
		if(j==1 || j==m) c[j]=1.0/3*c[j]+1;
		else c[j]=1.0/4*c[j]+1;
	}

	w[1][1]=2.0/3, w[1][2]=-1.0/3;
	w[m][m-1]=-1.0/3, w[m][m]=2.0/3;
	rep(i,2,m-1) w[i][i]=3.0/4, w[i][i-1]=w[i][i+1]=-1.0/4;
	rep(i,2,m){
		double k=w[i][i-1]/w[i-1][i-1];
		rep(j,i-1,i) w[i][j]-=k*w[i-1][j]; 
		c[i]-=k*c[i-1];
	}
	dwn(i,m-1,1){
		double k=w[i][i+1]/w[i+1][i+1];
		w[i][i+1]=0;
		c[i]-=k*c[i+1];
	} 
	rep(j,1,m) y[j]=c[j]/w[j][j], c[j]=y[j];
}

int main(){
	cin>>n>>m>>tx>>ty;
	rep(i,1,m) c[i]=0;
	
	int tot=n-tx;
	if(m==1) return printf("%.4lf\n", 2.0*tot), 0;
	while(tot--) get();
	printf("%.4lf\n", c[ty]);
	return 0;
}
posted @ 2022-03-04 11:58  HinanawiTenshi  阅读(52)  评论(0编辑  收藏  举报