矩阵快速幂
基础概念
利用矩阵快速幂加快递推式的计算
对于形如\(f(n)=af(n-1)+bf(n-2)+cf(n-3)+df(n-4)+...\)的递推式,以\(f(n)=af(n-1)+bf(n-2)+cf(n-3)+df(n-4)\)为例,我们可以利用矩阵快速幂的方式加快递推式的计算。
首先得出一个矩阵定义式:
\[A(n)=[f(n),f(n-1),f(n-2),f(n-3)],B为4*4方阵
\]
B的大小由递推项的个数决定,例子f(n)由4项组成,所以B为4*4方阵
矩阵递推式:
\[A(n)=A(n-1)*B
\]
A矩阵初项:
\[A(4)=[1,1,1,1]
\]
B矩阵,首列为原递推式的对应系数,除第一列,最后一行以外右上部分为单位阵
\[B=\begin{bmatrix}
a&1&0&0\\
b&0&1&0\\
c&0&0&1\\
d&0&0&0\\
\end{bmatrix}
\]
最终:
\[A(n)=A(4)*B^{n-1}
\]
则,最终的f(n)就是B的第一列和(前4项不一定成立,需特判)
板子
2023.8 最新整理板子 2
int n;
const int mod = 998244353;
struct Matrix{
static const int N = 15;
ll a[N][N];
Matrix(ll e = 0){
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= n; ++ j)
a[i][j] = e * (i == j);
}
Matrix mul(Matrix A, Matrix B){
Matrix ans(0);
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= n; ++ j){
for(int k = 1; k <= n; ++ k){
ans.a[i][j] = (ans.a[i][j] + A.a[i][k] * B.a[k][j]) % mod;
}
}
}
return ans;
}
Matrix ksm(Matrix A, ll b){
Matrix ans(1);
while(b){
if(b & 1) ans = mul(ans, A);
A = mul(A, A);
b >>= 1;
}
return ans;
}
};
板子1
全部功能外置,记得给矩阵赋初值
const int N=2;
struct matrix{
int m[N][N];
};
matrix operator *(const matrix a,const matrix b){
matrix c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<N;++i){
for(int j=0;j<N;++j){
for(int k=0;k<N;++k){
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
}
}
}
return c;
}
matrix qpow_matrix(matrix a,int x){
matrix c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<N;++i) c.m[i][i]=1;
while(x){
if(x&1) c=c*a;
a=a*a;
x>>=1;
}
return c;
}
板子2,利用struct聚合
记得给n赋值
struct Matrix{
static const int N=15;
ll a[N][N];
Matrix(ll e=0){
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=e*(i==j);
}
Matrix mul(Matrix A,Matrix B){
Matrix ans(0);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
ans.a[i][j]=(ans.a[i][j]+A.a[i][k]*B.a[k][j])%mod;
}
}
}
return ans;
}
Matrix ksm(Matrix A,ll b){
Matrix ans(1);
while(b){
if(b&1) ans=mul(ans,A);
A=mul(A,A);b>>=1;
}
return ans;
}
}tmp;
相关习题
- Fibonacci
矩阵快速幂加速递推模板题,前提就是找到那个基础的矩阵
此题,\(n≥2\)时,\(A=\begin{bmatrix} 1&1\\ 1&0\\ \end{bmatrix}\),\(A^n={\begin{bmatrix} F_{n+1}&F_n\\ F_n&F_{n-1}\\ \end{bmatrix}}^n\)
所以\(F_n\)即为左下角的第一个数
\(F_0与F_1\)已经给定了
下见代码:
//>>>Qiansui
#include<map>
#include<set>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
const int maxm=2e5+5,inf=0x3f3f3f3f,mod=10000,N=2;
struct matrix{
int m[N][N];
};
matrix operator *(const matrix a,const matrix b){
matrix c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<N;++i){
for(int j=0;j<N;++j){
for(int k=0;k<N;++k){
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
}
}
}
return c;
}
matrix qpow_matrix(matrix a,int x){
matrix c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<N;++i) c.m[i][i]=1;
while(x){
if(x&1) c=c*a;
a=a*a;
x>>=1;
}
return c;
}
void solve(){
int c;
matrix a,b;
a.m[0][0]=1;
a.m[0][1]=1;
a.m[1][0]=1;
a.m[1][1]=0;
while(cin>>c){
if(c==-1) break;
b=qpow_matrix(a,c);
cout<<b.m[1][0]<<"\n";
}
return ;
}
signed main(){
//ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
// cin>>_;
while(_--){
solve();
}
return 0;
}
- Geometric Progression
乍一眼是乘法逆元,但是并不是每个数都存在乘法逆元。
这题得先观察一个规律——\(\begin{pmatrix} a_X\\ 1\\ \end{pmatrix}=\begin{pmatrix} A&1\\ 0&1\\ \end{pmatrix}^X \begin{pmatrix} 0\\ 1\\ \end{pmatrix}\),之后利用矩阵快速幂求解
详见提交代码
本文来自博客园,作者:Qiansui,转载请注明原文链接:https://www.cnblogs.com/Qiansui/p/17383064.html