经过漫长(并不务正业)的暑假,我终于回归了OI。
下面以此代码为例子:Luogu4910
#include <cstdio> #include <cstring> typedef long long ll; const ll MOD = 1000000007; ll fbi[5][5] = {{1,1,0,0,0}, {1,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} }; ll fir[5][5] = {{1,1,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} }; struct mat{ ll a[5][5]; int m,n;//行数,列数 mat(ll x[5][5],int m1,int n1){ for(int i = 0 ; i < m1; i ++){ for(int j = 0 ; j < n1 ; j++){ a[i][j] = x[i][j]; } } m = m1; n = n1; } mat(int m1, int n1, bool one){ for(int i = 0; i < m1; i ++){ for(int j = 0 ; j < n1 ; j++){ a[i][j] = 0; if(i == j && one == true) a[i][j] = 1; } } m = m1; n = n1; } }; ll FIB(int N); void print(mat a); mat matmul(mat a,mat b) { if(a.n != b.m) return mat(5,5,false); mat ret(a.m,b.n,false); for(int i = 0 ; i < a.m; i ++){ for(int j = 0; j < b.n; j ++){ for(int k = 0; k < a.n; k++){ ret.a[i][j] += a.a[i][k] * b.a[k][j]; ret.a[i][j] %= MOD; } } } return ret; } int n; mat poww(mat a,int b){ mat ret(2,2,true); while(b){ if(b&1 == 1) ret = matmul(a,ret); a = matmul(a,a); b>>=1; } return ret; } mat calc(int N){ if(N == 1 || N == 2) return mat(1,2,true); mat firmat(fir,1,2); mat fb(fbi,2,2); mat res = poww(fb,N-1); mat ret = matmul(firmat,res); return ret; } void print(mat a){ printf("--------printf-------- "); for(int i = 0 ; i < a.m ; i ++){ for(int j = 0; j < a.n; j ++){ printf("%d ",a.a[i][j]); } printf(" "); } printf("---------end---------- "); } ll getans(int N){ if(N == 1) return 2; mat M = calc(N-1); //print(M); return ((M.a[0][1]+M.a[0][0])%MOD+M.a[0][1])%MOD; //return FIB(n+1)+FIB(n-1); } int t; ll FIB(int N){ ll a = 1; ll b = 1; if(N < 3) return 1; for(int i = 3; i <= N; i++){ ll tmp = b; b = (a+b)%MOD; a = tmp; } return b; } int main() { scanf("%d",&t); //calc(t); for(int i = 0 ; i < t ; i++){ scanf("%d",&n); printf("%lld ",getans(n)); } /* test /* n = 1000000000; printf("fast: "); printf("%lld ",calc(n)); printf("slow: "); printf("%lld ",FIB(n)); */ return 0; }
所谓矩阵快速幂,就是快速幂和矩阵的合体。传统的快速幂是将一个数分为a^1 * a^2 * a^4...,从而进行快速幂计算。而矩阵快速幂,求的是矩阵的幂,由于矩阵乘法也满足类似性质,所以只要给定幂次,再将幂次分解,线性递推出就能矩阵的二的n次幂的幂,用相同于快速幂的方法即可求解。对于一些数论计算和递推题目可以利用矩阵快速幂优化。