1. 关键问题在于如何去建立关系矩阵,观察本题,可以发现n与m非常小,因此,可以
将整个矩阵压缩成 一行 (m*n + 1)列
num(i,j) = (i - 1) * m + j; 代表压缩后各坐标在这个行列式中的位置。
2.接着思考如何使用矩阵快速幂加快运算。
注意到最长长度为6,1 - 6 最小公倍数为 6,因此我们每个60秒可以理解为一个周期,那么将t拆成
, 用A 表示每个60秒内的关系矩阵,便可计算 加快运算。
3. 对于60秒内的各个关系矩阵,我们可以初始创找一个对角矩阵(利用对角矩阵乘任何数为其本身的性质)因此乘每一秒的关系矩阵即可。最关键的就是关系矩阵如何抽象。
我们以 a[t][i][j] 代表t秒时刻的关系矩阵,对于(i,j)这点的上移操作,我们令 a[t][num(i,j)]【num(i,j-1)】= 1,(不妨自己画个矩阵试一下),这样便在矩阵相乘的时候可以可以模拟上移操作,其他同理。
4.特殊的,我们令每个时刻的第0行,第零列为1,可以将其理解为进行(给予石头操作时候的源头),在查询答案时我们查询的是(1,n + m),第0行对答案没有影响。然而对于添加操作的时候我们便可以令a[t][0][num(i,j)] = 0.,便可以实现添加操作(可以自己画图试一下)。
下附代码。
#include<bits/stdc++.h>
using namespace std;
const int MAX_NM = 65;
typedef long long ll;
int n,m,t,act;
string opt[10];
string acts[10];
ll f[MAX_NM];
ll a[MAX_NM][MAX_NM][MAX_NM];
ll A[MAX_NM][MAX_NM];
// 0 - n * m
inline int num(int i, int j)
{
return (i-1)*m + j;
}
void Mul(ll f[MAX_NM], ll a[MAX_NM][MAX_NM])
{
ll c[MAX_NM];
memset(c, 0, sizeof c);
for (int j = 0; j < MAX_NM; j++)
for (int k = 0; k < MAX_NM; k++)
c[j] += f[k] * a[k][j];
memcpy(f, c, sizeof c);
}
void mulb(ll a[MAX_NM][MAX_NM], ll b[MAX_NM][MAX_NM])
{
ll c[MAX_NM][MAX_NM];
memset(c, 0, sizeof c);
for (int i = 0; i < MAX_NM; i++)
for (int j = 0; j < MAX_NM; j++)
for (int k = 0; k < MAX_NM; k++)
c[i][j] += a[i][k]*b[k][j];
memcpy(a, c, sizeof c);
}
void mulself(ll a[MAX_NM][MAX_NM])
{
ll c[MAX_NM][MAX_NM];
memset(c, 0, sizeof c);
for (int i = 0; i < MAX_NM; i++)
for (int j = 0; j < MAX_NM; j++)
for (int k = 0; k < MAX_NM; k++)
c[i][j] += a[i][k]*a[k][j];
memcpy(a, c, sizeof c);
}
void init()
{
for(int tt = 0 ; tt < 60 ; tt++)
{
for(int i = 1 ; i <= n ; i++)
{
for(int j = 1 ; j <= m ; j++)
{
int ix = opt[i - 1][j - 1] - '0';
int iy = tt % acts[ix].size(); //提取操作
char ch =acts[ix][iy];
if(isupper(acts[ix][iy]))
{
if(ch == 'N' && i > 1) a[tt][num(i,j)][num(i-1,j)] = 1;
else if(ch =='S'&&i < n) a[tt][num(i,j)][num(i+1,j)] = 1;
else if(ch =='E' && j < m) a[tt][num(i,j)][num(i,j + 1)] = 1;
else if(ch == 'W' && j > 1) a[tt][num(i,j)][num(i,j - 1)] = 1;
else if(ch == 'D') a[tt][num(i,j)][num(i,j )] = 0;
}
if(isdigit(ch))
{
a[tt][0][0] = 1;
a[tt][num(i,j)][num(i,j)] = 1;
a[tt][0][num(i,j)] = ch - '0';
}
}
}
}
for(int i = 0 ; i < MAX_NM; i++) A[i][i] = 1;
for(int aq = 0 ; aq < 60 ; aq++) mulb(A,a[aq]);
}
int main()
{
cin >> n >> m >> t >> act;
for (int i = 0; i < n; i++)
cin >> opt[i];
for (int i = 0; i < act; i++)
cin >> acts[i];
f[0] = 1;
init();
int az = t/60;
t -= az * 60;
if(az)
{
for(;az;az>>=1)
{
if(az&1) Mul(f,A);
mulself(A);
}
}
for(int i = 0 ; i < t ;i++) Mul(f,a[i]);
ll ans = 0;
for(int i = 1 ; i < MAX_NM;i++)
ans = max(ans,f[i]);
cout << ans << endl;
}