CodeForces 24D Broken robot(三对角矩阵)

时间:2022-11-16 08:09:02

题意:给你一个n×m的矩阵,以及起点i,j,问你走到最后一行的步数期望,可以向下左右(当然不能跃出矩阵)或者在当前位置不动,也算一步。

解法:其实这题我们能很快写出递推式。最后一行的每个期望都为0,我们靠这个往上推。例如当m等于6时。 

x1 x2 x3 x4 x5 x6

y1 y2 y3 y4 y5 y6

对于x1来说,x1 = 1/3x1+1/3x2+1/3y1+1。对于x2到x5来说,xi = 1/4xi+1/4x(i-1)+1/4x(i+1)+1/4yi+1。对于x6来说,x6 = 1/3x6+1/3x5+1/3y6+1。

这样我们可以列出n组变量为m个的方程。考虑到n×m的数量高达10^6,所以不能用高斯消元求解。这里就要引入一个方法了。就是三对角矩阵。详细了解可以看这条链接。

http://www.cnblogs.com/xpvincent/archive/2013/01/25/2877411.html

不难看出其实我们列的这个方程就是三对角矩阵。例如xi = 1/4xi+1/4x(i-1)+1/4x(i+1)+1/4yi+1。我们可以变形成:

- 1/4x(i-1) + 3/4xi -1/4x(i+1) = 1/4yi + 1。系数分别对应a[i],b[i]和c[i]。

至此就可以用o(n*m)方法解决这道题了。公式其实并不需要记,自己推一下就可得了。

另外,有一个坑点,当m为1的时候,是需要特判的。这样的话,可得公式 xi = x(i+1)+2。

AC代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll __int64
#define ull unsigned long long
#define eps 1e-8
#define NMAX 1000000000
#define MOD 1000000
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x.end())
template<class T>
inline void scan_d(T &ret)
{
char c;
int flag = 0;
ret=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c == '-')
{
flag = 1;
c = getchar();
}
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
if(flag) ret = -ret;
}
template<class T> inline T Max(T a, T b){ return a > b ? a : b; }
template<class T> inline T Min(T a, T b){ return a < b ? a : b; }
const int maxn = 1005;
double a[maxn],b[maxn],c[maxn];
int n,m;
double x[maxn][maxn];
void init()
{
b[1] = 2.0/3.0; c[1] = -1.0/3.0;
a[m] = -1.0/3.0; b[m] = 2.0/3.0;
for(int i = 2; i < m; i++)
{
a[i] = -1.0/4.0;
b[i] = 3.0/4.0;
c[i] = -1.0/4.0;
}
for(int i = 1; i <= m; i++)
x[n][i] = 0;
}
double r[maxn],p[maxn];
int main()
{
#ifdef GLQ
freopen("input.txt","r",stdin);
// freopen("o.txt","w",stdout);
#endif
int t1,t2;
scanf("%d%d%d%d",&n,&m,&t1,&t2);
if(m == 1)
{
double x = 0;
for(int i = n; i > t1; i--)
x = x+2.0;
printf("%.6lf\n",x);
return 0;
}
init();
for(int i = n; i > t1; i--)
{
x[i][1] = x[i][1]/3.0+1.0;
x[i][m] = x[i][m]/3.0+1.0;
for(int j = 2; j < m; j++)
x[i][j] = x[i][j]/4.0+1.0;
r[1] = c[1]/b[1];
p[1] = x[i][1]/b[1];
for(int j = 2; j < m; j++)
r[j] = c[j]/(b[j]-a[j]*r[j-1]);
for(int j = 2; j <= m; j++)
p[j] = (x[i][j]-a[j]*p[j-1])/(b[j]-a[j]*r[j-1]);
// cout<<p[m]<<endl;
x[i-1][m] = p[m];
for(int j = m-1; j >= 1; j--)
x[i-1][j] = p[j]-x[i-1][j+1]*r[j];
}
printf("%.6lf\n",x[t1][t2]);
return 0;
}