矩阵乘法经典例题。
做一个映射
把网格看成长度为的一维向量,定义一个 行 列的状态矩阵 ,将其转换成一维数组 。
表示网格的 位置石子个数, 初始化1且始终为1,象征着给别的网格分发石子的“上帝”。
操作长度不超过6,1~6的最小公倍数为60,所以每经过60秒,每个网格的操作序列一定处于最开始的字符处。
因此可以把1~60的操作矩阵相乘,再快速幂算它的 次方,再乘以剩下的1到 秒的操作矩阵,再被初始的状态矩阵 乘即可。注意顺序不能错!!!!
构造操作矩阵很简单,设 为第 k 秒的操作矩阵。将其定义成行列的矩阵,及一个二维数组。
表示映射为x的网格在第k秒对映射为y的网格的影响。
说几个坑点:
1、注意WESN这些挪石子会挪出边界,此时应该直接抛弃这些石子,否则在转移矩阵上会错误的移往别的位置。
2、 注意开long long,会爆int
3、long long用%lld输出
4、用来参加乘法的矩阵初始化应该是单位阵,而不是零阵
5、数字之间没有空格时不能用scanf("%d")!!! sacnf("%c") 会读取换行符,记得getchar()!!
6、矩阵乘法没有交换律!!!!!!!!
整个过程的矩阵乘法是
可以先做一个60的循环算出
在这个过程中可以顺便把 算出来
如果 那我们不用算出,把 算出来后,此时的 并不是完整的,但是(单位阵), 仍是正确答案;
当 时,一定要注意是 而不是 ,调了半天,吐血。。。
#include <cstdio>
#include <string>
#include <iostream>
#include <cstring>
#include <algorithm>
#define LL long long
#define mc(a,b) memcpy(a,b,sizeof(b))
#define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=71;
LL A[N][N],f[N],sum[N][N],extra[N][N];
int n,m,t,act,ac[11][11];
string s[15];
int cal(int x,int y)
{return (x-1)*n+y;}
void mul1(LL a[N][N],LL b[N][N])
{
LL c[N][N];
ms(c,0);
for(int i=0;i<=n*m;i++)
for(int j=0;j<=n*m;j++)
for(int k=0;k<=n*m;k++) c[i][j]+=a[i][k]*b[k][j];
mc(a,c);
}
void mul2(LL a[N],LL b[N][N])
{
LL c[N];
ms(c,0);
for(int j=0;j<=n*m;j++)
for(int k=0;k<=n*m;k++) c[j]+=a[k]*b[k][j];
mc(a,c);
}
void qpow(LL a[N][N],int b)
{
LL c[N][N];
ms(c,0);//中间矩阵初始化
for(int i=0;i<=n*m;i++)
c[i][i]=1;
while(b)
{
if(b&1)
mul1(c,a);
b>>=1;
mul1(a,a);
}
mc(a,c);//中间矩阵还原给传递过来的矩阵
}
int main()
{
f[0]=1;
scanf("%d%d%d%d",&n,&m,&t,&act);
getchar();//scanf不读最后的空格
for(int i=1;i<=n;i++)//连在一起的数字不能直接用scanf integer,读入char=,再转换
{
for(int j=1;j<=m;j++)
{
char c;
scanf("%c",&c);//有scanf char 注意是否有换行
ac[i][j]=c-'0';
}
getchar();
}
for(int i=0;i<act;i++)
cin>>s[i];
for(int i=0;i<=n*m;i++)
extra[i][i]=sum[i][i]=1;
for(int it=0;it<60&&it<t;it++)
{
ms(A,0);
A[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
string tmp=s[ac[i][j]];
char tmpp=tmp[it%tmp.size()];
int pos=cal(i,j);
if(tmpp=='D') continue;
if(tmpp>='0'&&tmpp<='9')
{
A[0][pos]=tmpp-'0';
A[pos][pos]=1;
}
else
{
if(tmpp=='E'&&j<m)
A[pos][cal(i,j+1)]=1;
if(tmpp=='W'&&j>1)
A[pos][cal(i,j-1)]=1;
if(tmpp=='N'&&i>1)
A[pos][cal(i-1,j)]=1;
if(tmpp=='S'&&i<n)
A[pos][cal(i+1,j)]=1;
}
}
mul1(sum,A);
if((it+1)==(t%60))
mc(extra,sum);
}
int cnt=t/60;
qpow(sum,cnt);
mul2(f,sum);
mul2(f,extra);
LL maxn=0;
for(int i=1;i<=n*m;i++)
maxn=max(maxn,f[i]);
printf("%lld",maxn);
}