矩阵加速线性递推
斐波那契数列
定义
为斐波那契数列第 项,斐波那契数列定义如下 给定一个
,求出 的值。其中 。
此题的一个经典做法是递推,时间复杂度为
定义一个矩阵
定义一个矩阵
我们就会发现
也就是说,
关于矩阵乘法:
计算两个矩阵的乘法。
例题
做法还是矩阵加速递推,定义
另外千万记得在写矩阵乘法是一定要记得初始化。
点击查看代码
#include <iostream>
#include <cstring>
#define int long long
using namespace std;
const long long mod=1e9+7;
int f[3],a[3][3],n,q;
void cheng1(){//矩阵F*矩阵A
int c[3];
memset(c,0,sizeof(c));
for(int i=0;i<=2;i++){
for(int j=0;j<=2;j++){
c[i]=(long long)(c[i]+f[j]*a[i][j])%mod;
}
}
for(int i=0;i<=2;i++)f[i]=c[i];
return;
}
void cheng2(){//矩阵A*矩阵A
int b[3][3];
memset(b,0,sizeof(b));
for(int i=0;i<=2;i++){
for(int j=0;j<=2;j++){
for(int k=0;k<=2;k++){
b[i][j]=(long long)(b[i][j]+a[i][k]*a[k][j])%mod;
}
}
}
for(int i=0;i<=2;i++)for(int j=0;j<=2;j++)a[i][j]=b[i][j];
return;
}
void ksm(int b){//ksm
while(b){
if(b&1)cheng1();
cheng2();
b>>=1;
}
return;
}
signed main(){
cin>>q;
while(q--){
cin>>n;
a[0][0]=0,a[0][1]=1,a[0][2]=0,a[1][0]=0,a[1][1]=0,a[1][2]=1,a[2][0]=1,a[2][1]=0,a[2][2]=1,f[1]=1,f[2]=1,f[0]=0;
ksm(n);
cout<<f[0]<<endl;
}
return 0;
}
可以看出矩阵乘法优化线性递推的特点是,递推的每一项只会与前面若干项取值相关。矩阵乘法的递推难点主要在于构建矩阵
另外矩阵快速幂的时间复杂度不是标准的
例题
矩阵
很多递推的矩阵
例题
对于这种在递推中要加一个常数项的情况,在矩阵
例题
本题的目标是
我们另
矩阵
我们不妨思考一下,
上面式子太抽象,举个例子:
当k=2时
F[n]=[s[n],s[n+1],s[n+2]]
s[n+3]=s[n+2]+a[n+3]
a[n+3]=c[1]*a[n+2]+c[2]*a[n+1]
a[n+3]=c[1]*(s[n+2]-s[n+1])+c[2]*(s[n+1]-s[n])
a[n+3]=c[1]*s[n+2]-c[1]*s[n+1]+c[2]*s[n+1]-c[2]*s[n]
s[n+3]=s[n+2]*(c[1]+1)+s[n+1]*(c[2]-c[1])+s[n]*(-c[2])
把他们拆开,计算每一个
- 对于剩下的
,
按照上述思路,就可以写出矩阵
我们以样例为例
0 1 0
0 0 1
-1 0 2
这就是样例的矩阵
最后的代码在过程中不断取模就可以了
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll k,n,m,b[25],c[25],mod,f[25],a[25][25];
inline ll read(){
ll r=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')r=(r<<1)+(r<<3)+(ch^48),ch=getchar();
return r;
}
void write(ll r){
if(r>9)write(r/10);
putchar(r%10+'0');
return;
}
void init(){
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
for(int i=2;i<=k+1;i++)f[i]=b[i-1]+f[i-1];
for(int i=1;i<=k;i++)a[i][i+1]=1;
for(int i=1;i<=k+1;i++){
if(i==1)a[k+1][i]=-c[k];
else if(i==k+1)a[k+1][i]=c[1]+1;
else a[k+1][i]=c[k-i+2]-c[k-i+1];
}
return;
}
//省略一部分
int main(){
k=read();
for(int i=1;i<=k;i++)b[i]=read();
for(int i=1;i<=k;i++)c[i]=read();
m=read(),n=read(),mod=read();
write(((ksm(n)-ksm(m-1))%mod+mod)%mod);
return 0;
}
蒟蒻第一个不看题解过掉的紫题
例题
矩阵加速优化动态规划。
在本题中,我们令
在
注意到
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int mod=1e9+7,N=1e5+10;
ll f[30],a[30][30],n;
char s[N];
int ksm(ll b){
ll cnt=0;
while(b){
if(b&1)cheng1();
cheng2();
b>>=1;
}
for(int i=1;i<=26;i++)cnt=(cnt+f[i])%mod;
return cnt;
}
//省略一部分
int main(){
scanf("%lld",&n);
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=26;i++)for(int j=1;j<=26;j++)a[i][j]=1;
for(int i=2;i<=len;i++){
a[s[i]-'a'+1][s[i-1]-'a'+1]=0;
}
for(int i=1;i<=26;i++)f[i]=1;
cout<<ksm(--n)<<endl;
return 0;
}
小结
矩阵乘法加速递推可以说是我第一个学明白的数论算法了,虽然感觉在实战中的使用率不大,但是还是感觉是一个很有用的算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!