矩阵乘法。

1. 关键问题在于如何去建立关系矩阵,观察本题,可以发现n与m非常小,因此,可以

将整个矩阵压缩成 一行 (m*n + 1)列

num(i,j) = (i - 1) * m + j; 代表压缩后各坐标在这个行列式中的位置。

2.接着思考如何使用矩阵快速幂加快运算。

注意到最长长度为6,1 - 6 最小公倍数为 6,因此我们每个60秒可以理解为一个周期,那么将t拆成

q * 60 + res,  用A 表示每个60秒内的关系矩阵,便可计算A^q 加快运算。

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;

 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值