欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
题目可以理解为是一个
n
∗
m
n*m
n∗m的矩阵,在里面进行一些玄学的操作。
不难发现,操作序列的长度不超过6,那么1~6的最小公倍数是60,
即每经过60秒,所有操作序列都会重新处于最开始的字符处。
那么第 k ( 1 ≤ k ≤ 60 ) k(1\le k\le 60) k(1≤k≤60)秒,第 k + 60 k+60 k+60秒执行的字符与第 k k k秒一定是相同的。
得到了这个结论,我们就可以很容易想到递推,因为这是单调的。
之后发现递推中都是加法。
之后我们就可以运用矩阵乘法来加速运算。
设状态矩阵为 F F F,我们用这样的方法去表示 i i i行 j j j列的石头数:
F [ n u m ( i , j ) ] , n u m ( i , j ) = ( i − 1 ) ∗ m F[num(i,j)],num(i,j)=(i-1)*m F[num(i,j)],num(i,j)=(i−1)∗m
根据题目定义,我们可以得到 F F F的初始状态是 [ 0 0 . . . 0 ] \begin{bmatrix}0&0&...&0\end{bmatrix} [00...0]
我们不妨多一个源点 p = n ∗ m + 1 p=n*m+1 p=n∗m+1,使 F [ p ] = 1 F[p]=1 F[p]=1.
因为矩阵乘法,必须要有一个不为 1 1 1的数,才能正常进行操作,否则操作等于无效
那我们也需要一个转移矩阵 A A A来转移状态吧。
对于第 k ( 1 ≤ k ≤ 60 ) k(1\le k\le60) k(1≤k≤60)秒,构造一个转移状态 A k A_k Ak,行,列下标均为 1 1 1~ n ∗ m + 1 n*m+1 n∗m+1
构造方法类似于跑图:
-
若网格 ( i , j ) (i,j) (i,j)第k秒的操作字符为“N”,且 i > 1 i>1 i>1,则令 A k [ n u m ( i , j ) , n u m ( i − 1 , j ) ] = 1 A_k[num(i,j),num(i-1,j)]=1 Ak[num(i,j),num(i−1,j)]=1,意思就是把石头推到上边的格子。字符"W",“S”,"E"类似。
-
若网格 ( i , j (i,j (i,j)第 k k k秒的操作字符时一个数字 x x x,则令 A k [ 0 , n u m ( i , j ) ] = x A_k[0,num(i,j)]=x Ak[0,num(i,j)]=x。
-
令 A k [ p , p ] = 1 A_k[p,p]=1 Ak[p,p]=1。
-
A k A_k Ak的其它部分均赋值为 0 0 0.
上述结构实际上把“状态矩阵”的第 p p p列作为“石头来源”, A k [ p , p ] = 1 A_k[p,p]=1 Ak[p,p]=1保证 F [ p ] = 1 F[p]=1 F[p]=1
A k [ p , n u m ( i , j ) ] = x A_k[p,num(i,j)]=x Ak[p,num(i,j)]=x相当于从“石头来源”获取 x x x个石头,放到格子 ( i , j ) (i,j) (i,j)上。
设
A
=
∏
i
=
1
60
A
i
,
t
=
q
(
60
+
r
(
0
≤
r
<
60
)
A=\prod\limits_{i=1}^{60}A_i,t=q(60+r(0\le r<60)
A=i=1∏60Ai,t=q(60+r(0≤r<60).根据上面的讨论:
F
t
=
F
0
∗
A
q
∗
∏
i
=
1
r
A
i
F_t=F_0*A^q*\prod\limits_{i=1}^rA_i
Ft=F0∗Aq∗i=1∏rAi
用矩阵乘法和快速幂计算该式, F t F_t Ft第 1 1 1~ n ∗ m n*m n∗m列中的最大值即为所求。
另外,对于 A k [ n u m ( i , j ) , n u m ( i − 1 , j ) ] = 1 A_k[num(i,j),num(i-1,j)]=1 Ak[num(i,j),num(i−1,j)]=1,其实也是另类建边,使石头能够“流过去”。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long
#define gc getchar()
using namespace std;
int n,m,t,act,p;
inline int num(int i,int j){return (i-1)*m+j;}
inline void muls(ll a[66][66],ll b[66][66])
{
ll w[66][66];memset(w,0,sizeof(w));
for(int i=1;i<=p;i++)
for(int k=1;k<=p;k++)
if(a[i][k])
for(int j=1;j<=p;j++)
w[i][j]+=a[i][k]*b[k][j];
memcpy(a,w,sizeof(w));
}
inline void mul(ll f[66],ll a[66][66])
{
ll w[66];memset(w,0,sizeof(w));
for(int j=1;j<=p;j++)/*for(int i=1;i<=p;i++)*/
for(int k=1;k<=p;k++)/*for(int j=1;j<=p;j++)*/
w[j]+=f[k]*a[k][j];/*w[i]=f[j]*a[j][i]*/
memcpy(f,w,sizeof(w));
}
char b[20][20],s[100];
ll f[66],e[66][66][66],d[66][66];int a[20][20],c[20][20];
int main()
{
scanf("%d%d%d%d",&n,&m,&t,&act);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)a[i][j]=s[j]-'0'+1;
}
for(int i=1;i<=act;i++)scanf("%s",b[i]);
p=n*m+1;
for(int k=1;k<=60;k++)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int x=a[i][j],y=c[i][j];
if(b[x][y]>='0'&&b[x][y]<='9')
{
e[k][p][num(i,j)]=b[x][y]-'0';
e[k][num(i,j)][num(i,j)]=1;
}
else if(b[x][y]=='N'&&i>1)e[k][num(i,j)][num(i-1,j)]=1;
else if(b[x][y]=='S'&&i<n)e[k][num(i,j)][num(i+1,j)]=1;
else if(b[x][y]=='W'&&j>1)e[k][num(i,j)][num(i,j-1)]=1;
else if(b[x][y]=='E'&&j<m)e[k][num(i,j)][num(i,j+1)]=1;
c[i][j]=(y+1)%strlen(b[x]);
}
e[k][p][p]=1;
}
memcpy(d,e[1],sizeof(e[1]));
for(int k=2;k<=60;k++)
muls(d,e[k]);
ll ans=0;
f[p]=1;int w=t/60;
while(w)
{
if(w&1)mul(f,d);
muls(d,d);
w>>=1;
}
w=t%60;
for(int i=1;i<=w;i++)mul(f,e[i]);
for(int i=1;i<p;i++)ans=max(ans,f[i]);
printf("%lld\n",ans);
return 0;
}