矩阵快速幂
在遇到一些递推式时,如果我们直接按公式一步步进行运算,效率较低。构造矩阵进行快速运算,可以高效地解决这个问题。
以int型方阵为例:
矩阵结构:
struct Mat{ int mat[n][n]; };
矩阵乘法:
Mat mul(Mat A,Mat B) { Mat ret; memset(ret.mat,0,sizeof(ret)); for(int i = 0; i<n; ++i) for(int j = 0; j<n; ++j) for(int k = 0; k<n; ++k) ret.mat[i][j] += A.mat[i][k]*B.mat[k][j]; return ret; }
快速计算方阵a的k次幂:
Mat matquickpow(Mat A,int k) { Mat ret; for(int i = 0; i<n; ++i) for(int j = 0; j<n; ++j) ret.mat[i][j] = (i == j); //初始化为单位矩阵 while(k){ if(k&1) ret = mul(ret,A); A = mul(A,A); k >>= 1; } return ret; }
快速计算方阵a的k次幂对mod取模的一步运算:
Mat mulmod(Mat A,Mat B,int mod) { Mat ret; memset(ret.mat,0,sizeof(ret)); for(int i = 0; i<n; ++i) for(int j = 0; j<n; ++j) for(int k = 0; k<n; ++k) ret.mat[i][j] = (ret.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod; //对于某些题目,当结果为负数不合题意时,可以对最终结果进行处理 //或者将此处改为ret.mat[i][j] = ((ret.mat[i][j]+a[i][k]*b[k][j])%mod+mod)%mod; return ret; }
快速计算方阵a的k次幂对mod取模:
Mat matquickpowmod(Mat A,int k,int m) { Mat ret; for(int i = 0; i<n; ++i) for(int j = 0; j<n; ++j) ret.mat[i][j] = (i == j); //初始化为单位矩阵 while(k){ if(k&1) ret = mulmod(ret,A); A = mulmod(A,A); k >>= 1; } return ret; }
例如,对于斐波那契数列的递推部分,我们可以运用矩阵快速幂进行计算:
将Fn+2 = Fn+Fn+1转换为
就可以运用矩阵快速幂进行计算了。