題面
題意
給出一個方格陣,初始每個格子中都沒有石頭,然後每個格子都有一個操作序列,並且每時刻執行一個,循環執行,序列長度小於等於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;
}