之前只做了快速幂取模,这次是矩阵。
就因为线代没怎么学,今天还花了一些时间去想为什么矩阵A^k+A^l=A^(k+l),是因为A^n=A^(n-1)*A=A^(n-2)*A*A=.....由于矩阵相乘满足结合律(可以以三个为例证明一下),所以可以任意取位置先后结合,所以有A^k+A^l=A^(k+l)。
两个矩阵相乘,复杂度是O(N^3),再乘M次,所以一个矩阵的M次方时间复杂度是O(N^3*M),如果用快速幂的思想,时间复杂度就可以变成O(N^3*logM).
//矩阵为N*N
struct Mat{ //定义矩阵
long long mat[N][N];
Mat(){
memset(mat,0,sizeof(mat));
}
};
Mat operator * (Mat a,Mat b){ //一次矩阵乘法
int i,j,k;
Mat ret;
for(k=0;k<N;k++){
for(i=0;i<N;i++){
if(a.mat[i][k]==0) continue;//剪枝,很重要
for(j=0;j<N;j++){
if(b.mat[k][j]==0) continue;
ret.mat[i][j]+=a.mat[i][k]*b.mat[k][j];//结果要取余时mod M
}
}
}
return ret;
}
Mat operator ^ (Mat a,int n){ //实现矩阵快速幂
Mat ret,t=a;
int i,j;
for(i=0;i<N;i++)
for(j=0;j<N;j++) ret.mat[i][j]=(i==j);
while(n){
if(n&1) ret=ret*t;
t=t*t;
n>>=1;
}
return ret;
}
实现矩阵快速幂的部分和快速幂很像,快速幂中ret初始化为1,t初始化为a^(2^0) mod M,这里ret初始化为单位矩阵(单位矩阵E乘A还为A),t就为要算N次幂的矩阵。
这个算法有一个用O(logn * 2^3)的复杂度算斐波那契数列,比普通的O(n)要快
f[0]=1
f[1]=1
f[2]=2
f[3]=3...
f[n]=f[n-1]+f[n-2]
网上找了个图
于是我们可以把a矩阵初始化,a.mat[0][0]=a.mat[0][1]=a.mat[1][0]=1,a.mat[1][1]=0,这样求出a^N,a.mat[0][0]的值就是f[N]。