矩阵快速幂
矩阵乘法
矩阵 A , B A,B A,B规模分别为 n × s , s × m n×s,s×m n×s,s×m,要进行矩阵乘法, A , B A,B A,B满足条件为"前列数=后行数"。 C C C为 A , B A,B A,B矩阵乘法结果,则C的规模变成 n × m n×m n×m, C C C第 i i i行第 j j j列的数字为A第i行每k个数乘B第j列每k个数: C ( i , j ) = ∑ k = 1 k = s A ( i , k ) × B ( k , j ) C(i,j)=\sum_{k=1}^{k=s}{A(i,k)×B(k,j)} C(i,j)=k=1∑k=sA(i,k)×B(k,j)
快速幂
如果要算3的21次方,不做任何优化:
3
×
3
=
9
,
9
×
3
=
27
,
27
×
3
=
81...
3×3=9,9×3=27,27×3=81...
3×3=9,9×3=27,27×3=81...一共做21次。
但是其实里面有很多重复计算的地方。让我们把21转化成2进制:
(
10101
)
2
(10101)_2
(10101)2观察。
如下图:
将21的二进制最后一位称作第一位,第一位是1,那答案包含
3
(
1
)
2
3^{(1)_2}
3(1)2,接下来计算
3
(
100
)
2
3^{(100)_2}
3(100)2,我们发现
(
100
)
2
(100)_2
(100)2是
(
1
)
2
(1)_2
(1)2左移2位,体现在底数,就是底数自乘2次。只要让3不断自乘,同时幂数不断右移,当幂数最后一位是1时,就将当前的底数乘到答案上即可。以上算法的时间复杂度是O(log幂数),因为n转化成二进制时的长度为log幂数。
设底数为a,幂数为b,一般答案会很大,一般会给你一个模数,在每次算出答案均取模。代码如下:
LL ksm(LL a,LL b){
LL ans=1;
while(b){
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
P3390 【模板】矩阵快速幂
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=110,mod=1e9+7;
int n;
struct Matrix{
LL x[N][N];
Matrix(){
memset(x,0,sizeof x);
}
};
Matrix operator*(const Matrix &a,const Matrix &b){
Matrix tmp;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
tmp.x[i][j]=(tmp.x[i][j]+a.x[i][k]*b.x[k][j]%mod)%mod;
return tmp;
}
Matrix Mksm(Matrix a,LL b){
Matrix ans;
for(int i=0;i<n;i++)
ans.x[i][i]=1;
while(b){
if(b&1)
ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
int main(){
LL k;
Matrix a;
cin>>n>>k;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>a.x[i][j];
Matrix b=Mksm(a,k);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout<<b.x[i][j]<<' ';
}cout<<endl;
}
return 0;
}