模板 - 数学 - 矩阵快速幂
线性递推公式找递推矩阵的方法:
https://blog.csdn.net/synapse7/article/details/18790165
构造方法:规定由递推矩阵A,左乘由项构成的矩阵F,其中矩阵A的第一列为对应系数,左下角为单位矩阵,右下角为零矩阵。
对于递推式的常数C,在矩阵F中增加最后一行C,在A的最右列增加两个1(通常选右上角和左下角)。
对于递推式的C的n次方,在矩阵F中增加最后一行C的n次方,在A的最右列增加两个C(通常选右上角和左下角)。
以斐波那契数列为例,这里使用了快速乘进一步防止溢出。
#include<bits/stdc++.h> using namespace std; #define ll long long #define MAXN 2 ll mod=1000000007; //快速乘 a*b%p 防止乘法溢出ll ll qmut(ll a,ll b){ ll res=0; while(b){ if(b&1) res=(res+a)%mod; a=(a+a)%mod; b>>=1; } return res; } class Matrix { public: ll m[MAXN][MAXN]; //二维数组存放矩阵 Matrix() { memset(m,0,sizeof(m)); } //对数组的初始化 void init(ll num[MAXN][MAXN]) { for(int i = 0 ; i < MAXN ; i++) { for(int j = 0 ; j < MAXN ; j++) { m[i][j] = num[i][j]; } } } Matrix operator*(Matrix &m1) { int i, j, k; Matrix t; for(i = 0; i < MAXN; i++) { for(j = 0; j < MAXN; j++) { t.m[i][j] = 0; for(k = 0 ; k < MAXN ; k++) t.m[i][j] = (t.m[i][j] + qmut(m[i][k],m1.m[k][j]))%mod; } } return t; } Matrix qpow(ll n) { Matrix t; for(int i = 0 ; i < MAXN ; i++) for(int j = 0 ; j < MAXN ; j++) t.m[i][j] = (i == j); Matrix M=*this; while(n) { if(n & 1) t = t * M; n = n >> 1; M = M * M; } return t; } void show() { for(int i=0; i<MAXN; i++) { for(int j=0; j<MAXN; j++) { cout<<m[i][j]<<" "; } cout<<endl; } cout<<endl; } }; int main() { ll n; cin>>n; if(n<=2){ cout<<1<<endl; return 0; } ll num[MAXN][MAXN]; Matrix A; memset(num,0,sizeof(num)); num[0][1]=num[1][0]=num[1][1]=1; A.init(num);//初始化A矩阵 //A.show(); Matrix ini; memset(num,0,sizeof(num)); num[0][0]=1; num[1][0]=1; ini.init(num); //ini.show(); Matrix An=A.qpow(n-2); //求出矩阵的快速幂 //An.show(); Matrix res=An*ini; //res.show(); cout<<res.m[1][0]<<endl; }
https://www.luogu.org/problemnew/show/P1939
#include<bits/stdc++.h> using namespace std; #define ll long long #define MAXN 4 ll mod=1000000007; //快速乘 a*b%p 防止乘法溢出ll ll qmut(ll a,ll b){ ll res=0; while(b){ if(b&1) res=(res+a)%mod; a=(a+a)%mod; b>>=1; } return res; } class Matrix { public: ll m[MAXN][MAXN]; //二维数组存放矩阵 Matrix() { memset(m,0,sizeof(m)); } //对数组的初始化 void init(ll num[MAXN][MAXN]) { for(int i = 0 ; i < MAXN ; i++) { for(int j = 0 ; j < MAXN ; j++) { m[i][j] = num[i][j]; } } } Matrix operator*(Matrix &m1) { int i, j, k; Matrix t; for(i = 0; i < MAXN; i++) { for(j = 0; j < MAXN; j++) { t.m[i][j] = 0; for(k = 0 ; k < MAXN ; k++) t.m[i][j] = (t.m[i][j] + qmut(m[i][k],m1.m[k][j]))%mod; } } return t; } Matrix qpow(ll n) { Matrix t; for(int i = 0 ; i < MAXN ; i++) for(int j = 0 ; j < MAXN ; j++) t.m[i][j] = (i == j); Matrix M=*this; while(n) { if(n & 1) t = t * M; n = n >> 1; M = M * M; } return t; } void show() { for(int i=0; i<MAXN; i++) { for(int j=0; j<MAXN; j++) { cout<<m[i][j]<<" "; } cout<<endl; } cout<<endl; } }; int main() { int T; while(~scanf("%d",&T)){ while(T--){ int n; scanf("%d",&n); if(n<=3){ printf("%d\n",1); continue; } ll num[MAXN][MAXN]; Matrix A; memset(num,0,sizeof(num)); num[0][1]=num[1][2]=num[2][3]=num[3][1]=num[3][3]=1; A.init(num);//初始化A矩阵 //A.show(); Matrix ini; memset(num,0,sizeof(num)); num[0][0]=1; num[1][0]=1; num[2][0]=1; num[3][0]=2; ini.init(num); //ini.show(); Matrix An=A.qpow(n-4); //求出矩阵的快速幂 //An.show(); Matrix res=An*ini; //res.show(); printf("%d\n",res.m[3][0]); } } }
带n的次方的矩阵快速幂,找出相邻两项的关系就可以,用杨辉三角就可以了。
#include<bits/stdc++.h> using namespace std; #define ll long long #define MAXN 8 ll mod=2147493647; class Matrix { public: ll m[MAXN][MAXN]; //二维数组存放矩阵 Matrix() { memset(m,0,sizeof(m)); } //对数组的初始化 void init(ll num[MAXN][MAXN]) { for(int i = 0 ; i < MAXN ; i++) { for(int j = 0 ; j < MAXN ; j++) { m[i][j] = num[i][j]; } } } Matrix operator*(Matrix &m1) { int i, j, k; Matrix t; for(i = 0; i < MAXN; i++) { for(j = 0; j < MAXN; j++) { t.m[i][j] = 0; for(k = 0 ; k < MAXN ; k++) t.m[i][j] = (t.m[i][j] + m[i][k]*m1.m[k][j]%mod)%mod; } } return t; } Matrix qpow(ll n) { Matrix t; for(int i = 0 ; i < MAXN ; i++) for(int j = 0 ; j < MAXN ; j++) t.m[i][j] = (i == j); Matrix M=*this; while(n) { if(n & 1) t = t * M; n = n >> 1; M = M * M; } return t; } void show() { for(int i=0; i<MAXN; i++) { for(int j=0; j<MAXN; j++) { cout<<m[i][j]<<" "; } cout<<endl; } cout<<endl; } }; int main() { int T; while(~scanf("%d",&T)) { while(T--) { ll n,a,b; scanf("%lld%lld%lld",&n,&a,&b); if(n==1) { printf("%lld\n",a); } else if(n==2) { printf("%lld\n",b); } else { ll num[MAXN][MAXN]; Matrix A; memset(num,0,sizeof(num)); num[0][0]=1; num[1][0]=1; num[1][1]=1; for(int i=2;i<=5;i++){ num[i][0]=1; for(int j=1;j<=i;j++){ num[i][j]=num[i-1][j-1]+num[i-1][j]; } } num[6][7]=1; num[7][5]=3; num[7][6]=3; num[7][7]=2; A.init(num);//初始化A矩阵 //A.show(); Matrix ini; memset(num,0,sizeof(num)); num[0][0]=1; num[1][0]=3; num[2][0]=9; num[3][0]=27; num[4][0]=81; num[5][0]=243; num[6][0]=a; num[7][0]=b; ini.init(num); //ini.show(); Matrix An=A.qpow(n-2); //求出矩阵的快速幂 //An.show(); Matrix res=An*ini; //res.show(); printf("%lld\n",res.m[7][0]); } } } }