题意:
是将n*k和k*n的矩阵的乘积,求n*n次方后求和。其中k<=6,n<=1000。
题解:
我一看完翻译就知道可以直接怼矩阵快速幂了,结果还是爆炸了,后来别人说是1000*1000的矩阵还是太大了,然后怎么优化呢?别人是这样做的,因为k=6,所以我们可以A*(B*A)^(n*n-1)*B。这样做,先B*A得到k阶的矩阵,因为k最大到6所以时间得到优化了。ORZ虽然这道题是基础题,但是让我学到了基础的矩阵公式变换和优化,下次就会注意了。
#include<stdio.h>
#include<string.h>
#define LL long long int
const int MOD=6;
int n,m;
struct node
{
LL m[10][10];
node()
{
memset(m,0,sizeof(m));
}
};
int a[1005][10],b[10][1005],c[1005][10],d[1005][1005];
node cla(node A,node B)
{
node C;
for(int i=0;i<m;i++)//A对应的行
for(int j=0;j<m;j++)//B对应的列
for(int k=0;k<m;k++)
if(A.m[i][k]&&B.m[k][j])//剪枝(添条件,设门槛),提高效率,有一个是0,相乘肯定是0
{
C.m[i][j]+=A.m[i][k]*B.m[k][j];
C.m[i][j]%=MOD;
}
return C;
}
node POW(int k,node ans)
{
node e;
for(int i=0;i<m;i++) e.m[i][i]=1;
while(k)
{
if(k%2) e=cla(e,ans);
ans=cla(ans,ans);
k/=2;
}
return e;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
break;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
memset(d,0,sizeof(d));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&a[i][j]);
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
scanf("%d",&b[i][j]);
node ans;
for(int i=0;i<m;i++)//A对应的行
for(int j=0;j<m;j++)//B对应的列
for(int k=0;k<n;k++)
if(b[i][k]&&a[k][j])//剪枝(添条件,设门槛),提高效率,有一个是0,相乘肯定是0
{
ans.m[i][j]+=b[i][k]*a[k][j];
ans.m[i][j]%=MOD;
}
ans=POW(n*n-1,ans);
for(int i=0;i<n;i++)//A对应的行
for(int j=0;j<m;j++)//B对应的列
for(int k=0;k<m;k++)
if(a[i][k]&&ans.m[k][j])//剪枝(添条件,设门槛),提高效率,有一个是0,相乘肯定是0
{
c[i][j]+=a[i][k]*ans.m[k][j];
c[i][j]%=MOD;
}
for(int i=0;i<n;i++)//A对应的行
for(int j=0;j<n;j++)//B对应的列
for(int k=0;k<m;k++)
if(c[i][k]&&b[k][j])//剪枝(添条件,设门槛),提高效率,有一个是0,相乘肯定是0
{
d[i][j]+=c[i][k]*b[k][j];
d[i][j]%=MOD;
}
int sum=0;
for(int i=0;i<n;i++)//A对应的行
for(int j=0;j<n;j++)//B对应的列
sum+=d[i][j];
printf("%d\n",sum);
}
}