题目链接:
HDU 4965 Fast Matrix Calculation
题意:
分别给出一个
n∗k
和
k∗n
的矩阵A和B,两矩阵相乘得到矩阵C,求出矩阵C的
n∗n
次幂矩阵M,
输出将矩阵M中每个元素%6后的元素和。其中n<1000,2<=k<=6.
分析:
因为n实在太大了,开不了1000*1000的矩阵,但是可以利用矩阵相乘的结合律,
A∗B∗A∗B∗A∗B∗A..∗A∗B
,可以将先计算中间的
B∗A∗B∗A∗..∗A
,这样B和A相乘得到的是一个6*6(最多)矩阵,
将这个矩阵用快速幂计算(n*n-1)次幂,在乘上一开始的A和最后的B即可。
//5512K 172MS
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1010;
int n,k,res;
int A[maxn][10],B[10][maxn],M[maxn][10],MM[maxn][maxn];
struct Matrix{
int row,col;
int data[10][10];
};
inline Matrix mul(Matrix a,Matrix b)
{
Matrix ans;
ans.row=a.row,ans.col=b.col;
memset(ans.data,0,sizeof(ans.data));
for(int i=1;i<=ans.row;i++){
for(int j=1;j<=ans.col;j++){
for(int p=1;p<=a.col;p++){
ans.data[i][j]+=a.data[i][p]*b.data[p][j]%6;
ans.data[i][j]%=6;
}
}
}
return ans;
}
inline Matrix quick_power(Matrix a,int m)
{
Matrix ans,tmp=a;
ans.row=ans.col=a.row;
memset(ans.data,0,sizeof(ans.data));
for(int i=1;i<=ans.row;i++) ans.data[i][i]=1;
while(m){
if(m&1) ans=mul(ans,tmp);
tmp=mul(tmp,tmp);
m>>=1;
}
return ans;
}
int main()
{
freopen("Ein.txt","r",stdin);
while(~scanf("%d%d",&n,&k)&&(n||k)){
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
scanf("%d",&A[i][j]);
}
}
for(int i=1;i<=k;i++){
for(int j=1;j<=n;j++){
scanf("%d",&B[i][j]);
}
}
Matrix ans;
ans.row=ans.col=k;
memset(ans.data,0,sizeof(ans.data));
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
for(int p=1;p<=n;p++){
ans.data[i][j]+=B[i][p]*A[p][j]%6;
ans.data[i][j]%=6;
}
}
}
ans=quick_power(ans,n*n-1);//中间部分矩阵乘积
memset(M,0,sizeof(M));
for(int i=1;i<=n;i++){//A*中间矩阵
for(int j=1;j<=k;j++){
for(int p=1;p<=k;p++){
M[i][j]+=A[i][p]*ans.data[p][j]%6;
M[i][j]%=6;
}
}
}
memset(MM,0,sizeof(MM));
for(int i=1;i<=n;i++){//再乘以最后的一个B数组
for(int j=1;j<=n;j++){
for(int p=1;p<=k;p++){
MM[i][j]+=M[i][p]*B[p][j]%6;
MM[i][j]%=6;
}
}
}
res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
res+=MM[i][j]%6;
}
}
printf("%d\n",res);
}
return 0;
}