题面
题意
给出一个方格阵,初始每个格子中都没有石头,然后每个格子都有一个操作序列,并且每时刻执行一个,循环执行,序列长度小于等于6,问T时刻后石头个数最多的格子中有几个石头。
做法
因为操作序列长度小于等于6,所以每60次操作必有一次循环,所以可以对60次操作建一个矩阵,由60次操作相乘,矩阵的长宽均为方格矩阵的元素总数,操作均可以用矩阵中的数字来表示,其中0号点用来表示所有石头的源头,然后矩阵快速幂即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 70
using namespace std;
ll m,n,tot,T,K,ans,num[N][N],len[N];
char cz[N][N];
struct Jz
{
ll num[N][N];
Jz(){memset(num,0,sizeof(num));}
Jz operator * (const Jz &u) const
{
ll i,j,k;
Jz res;
for(i=0;i<=tot;i++)
{
for(j=0;j<=tot;j++)
{
for(k=0;k<=tot;k++)
{
res.num[i][j]+=num[i][k]*u.num[k][j];
}
}
}
return res;
}
void out()
{
ll i,j;
for(i=0;i<=tot;i++)
{
for(j=0;j<=tot;j++)
{
printf("%-3lld",num[i][j]);
}
puts("");
}
puts("");
}
}qz[N],jz;
inline ll zh(ll u,ll v){return (u-1)*n+v;}
inline Jz po(Jz u,ll v)
{
ll i;
Jz res;
for(i=0;i<=tot;i++) res.num[i][i]=1;
for(;v;)
{
if(v&1) res=res*u;
u=u*u;
v>>=1;
}
return res;
}
int main()
{
ll i,j,k;
char t;
cin>>m>>n>>T>>K;
tot=m*n;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
scanf("%1lld",&num[i][j]);
num[i][j]++;
}
}
for(i=1;i<=K;i++)
{
scanf("%s",cz[i]);
len[i]=strlen(cz[i]);
}
for(i=0;i<=tot;i++) qz[0].num[i][i]=1;
for(i=1;i<=60;i++)
{
qz[i].num[0][0]=1;
for(j=1;j<=m;j++)
{
for(k=1;k<=n;k++)
{
t=cz[num[j][k]][(i-1)%len[num[j][k]]];
if(t>='0'&&t<='9')
{
qz[i].num[zh(j,k)][zh(j,k)]=1;
qz[i].num[0][zh(j,k)]=t-'0';
}
else if(t=='N'&&j>1) qz[i].num[zh(j,k)][zh(j-1,k)]=1;
else if(t=='S'&&j<m) qz[i].num[zh(j,k)][zh(j+1,k)]=1;
else if(t=='E'&&k<n) qz[i].num[zh(j,k)][zh(j,k+1)]=1;
else if(t=='W'&&k>1) qz[i].num[zh(j,k)][zh(j,k-1)]=1;
}
}
qz[i]=qz[i-1]*qz[i];
}
jz.num[0][0]=1;
jz=jz*po(qz[60],T/60)*qz[T%60];
for(i=1;i<=tot;i++) ans=max(ans,jz.num[0][i]);
cout<<ans;
}