一开始看这个题目以为是个裸的矩阵快速幂的题目,
后来发现会超时,超就超在 M = C^(N*N). 这个操作,而C本身是个N*N的矩阵,N最大为1000。
但是这里有个巧妙的地方就是 C的来源其实 是= A*B, A为一个N*k的矩阵,B为一个k*N的矩阵,k最大为10,突破的就在这里,矩阵的结合律要用起来
即我先不把A*B结合,我先把B*A结合,这样M不是要C^N*N吗,就先把里面N*N个(B*A)算出来,就10*10再乘以logN*N即可。最后再两端乘一下A和B即可
也挺机智的,我没想到结合律。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define LL __int64 using namespace std; LL matA[1010][10],matB[10][1010]; LL matC[1010][10]; LL MM[1010][1010]; int n,k; struct Mat { LL mat[10][10]; }E; Mat operator *(Mat a,Mat b) { Mat c; for (int i=0;i<k;i++) for (int j=0;j<k;j++){ c.mat[i][j]=0; for (int w=0;w<k;w++){ c.mat[i][j]+=a.mat[i][w]*b.mat[w][j]; c.mat[i][j]%=6; } } return c; } Mat operator ^(Mat a,int x) { Mat c=E; for (int i=x;i;i>>=1){ if (i&1){ c=c*a; } a=a*a; } return c; } int main() { memset(E.mat,0,sizeof E.mat); for (int i=0;i<10;i++) E.mat[i][i]=1; while (scanf("%d%d",&n,&k)!=EOF) { if (n==0 && k==0) break; for (int i=0;i<n;i++) for (int j=0;j<k;j++) scanf("%I64d",&matA[i][j]); for (int i=0;i<k;i++) for (int j=0;j<n;j++) scanf("%I64d",&matB[i][j]); Mat a; for (int i=0;i<k;i++) for (int j=0;j<k;j++){ a.mat[i][j]=0; for (int w=0;w<n;w++){ a.mat[i][j]+=matB[i][w]*matA[w][j]; } //cout<<i<<" aaa "<<j<<" "<<a.mat[i][j]<<endl; } Mat M=a^(n*n-1); for (int i=0;i<n;i++) for (int j=0;j<k;j++){ matC[i][j]=0; for (int w=0;w<k;w++) matC[i][j]+=matA[i][w]*M.mat[w][j]; // cout<<matC[i][j]<<" Matc "<<endl; } int ans=0; for (int i=0;i<n;i++) for (int j=0;j<n;j++){ MM[i][j]=0; for (int w=0;w<k;w++){ MM[i][j]+=matC[i][w]*matB[w][j]; } // cout<<MM[i][j]<<" qwe "<<endl; ans+=MM[i][j]%6; } printf("%d\n",ans); } return 0; }
时间: 2024-10-05 13:35:06