隐藏页面特效

Luogu P3390 【模板】矩阵快速幂&&P1939 【模板】矩阵加速(数列)

补一补之前的坑

因为上次关于矩阵的那篇blog写的内容太多太宽泛了,所以这次把一些板子和基本思路理一理

先看这道模板题:P3390 【模板】矩阵快速幂

首先我们知道矩阵乘法满足结合律而不满足交换律的一种运算

因此我们对于矩阵A的p次只需要先算出A^(p/2)即可

这不就是快速幂吗,快速幂的模板看这里

然后我们把其中的整数乘法改成矩阵乘法即可

关于矩阵的其他东西都不会,好吧,看一看概述矩阵

CODE

#include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int N=105,mod=1e9+7; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(LL &x) { x=0; char ch=tc(); while (ch<'0'||ch>'9') ch=tc(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc(); } inline void write(int x) { if (x/10) write(x/10); putchar(x%10+'0'); } struct Matrix { int n,m; LL a[N][N]; inline void input(void) { for (register int i=1;i<=n;++i) for (register int j=1;j<=m;++j) read(a[i][j]); } inline void output(void) { for (register int i=1;i<=n;++i,putchar('\n')) for (register int j=1;j<=m;++j) write(a[i][j]),putchar(' '); } inline void cri_init(void) { memset(a,0,sizeof(a)); for (register int i=1;i<=n;++i) a[i][i]=1; } }; LL k,n; inline Matrix mul(Matrix A,Matrix B) { Matrix C; C.n=A.n; C.m=B.m; memset(C.a,0,sizeof(C.a)); for (register int i=1;i<=C.n;++i) for (register int j=1;j<=C.m;++j) for (register int k=1;k<=A.m;++k) C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod; return C; } inline Matrix quick_pow(Matrix A,LL p) { Matrix T; T.n=T.m=n; T.cri_init(); while (p) { if (p&1) T=mul(T,A); A=mul(A,A); p>>=1; } return T; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); read(n); read(k); Matrix A; A.n=A.m=n; A.input(); A=quick_pow(A,k); A.output(); return 0; }

再看这道题:P1939 【模板】矩阵加速(数列)

主要讲一下矩阵与递推之间如何转化

首先我们看题目给出的式子:

  • a[1]=a[2]=a[3]=1

  • a[x]=a[x-3]+a[x-1] (x>3)

首先我们通过题目给出的初始值得到初始的列向量

1 a[1]
1 分别表示 a[2]
1 a[3]

我们发现,当前的这一项与它的前三项都有关,因此我们可以建立一个3*3的矩阵

然后因为a[4]=a[1]+a[3],而稍加推导可以将a[2]代替a[1]的位置,a[3]代替a[2]的位置

注意这里就很重要了,因为a[1]对于a[5]以及以后的推导没有任何作用了,因此可以直接被覆盖

可以结合滚动数组的思想进行一下理解

然后我们得出递推矩阵:

0 1 0
0 0 1
1 0 1

手推一下就会发现刚好完成了想要的效果

然后我们只需要把初始的列向量乘递推矩阵(n-3)次即可

矩阵快速幂求之

CODE

#include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int N=4,mod=1e9+7; struct Matrix { int n,m; LL a[N][N]; inline void Dt_init(void) { n=m=3; memset(a,0,sizeof(a)); a[1][2]=a[2][3]=a[3][1]=a[3][3]=1; } inline void cri_init(void) { n=m=3; memset(a,0,sizeof(a)); for (register int i=1;i<=n;++i) a[i][i]=1; } }; int t,n; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch=tc(); while (ch<'0'||ch>'9') ch=tc(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc(); } inline void write(int x) { if (x/10) write(x/10); putchar(x%10+'0'); } inline Matrix mul(Matrix A,Matrix B) { Matrix C; C.n=A.n; C.m=B.m; memset(C.a,0,sizeof(C.a)); for (register int i=1;i<=C.n;++i) for (register int j=1;j<=C.m;++j) for (register int k=1;k<=A.m;++k) C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod; return C; } inline Matrix quick_pow(Matrix A,int p) { Matrix T; T.cri_init(); while (p) { if (p&1) T=mul(T,A); A=mul(A,A); p>>=1; } return T; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); read(t); while (t--) { read(n); Matrix F; F.Dt_init(); if (n<=3) { puts("1"); continue; } F=quick_pow(F,n-3); write((F.a[3][1]+F.a[3][2]+F.a[3][3])%mod); putchar('\n'); } return 0; }

最后我们简单总结一下用矩阵乘法优化递推的步骤:

  1. 通过题目给出的关系得出线性递推关系

  2. 列出初始矩阵的值,通常根据初始条件确定

  3. 通过递推式,得到每一项的关系由那些地方转移过来,一般来说,就可以吧推得的当前项的项在矩阵中的位置附上1(如果有乘的关系就赋成负数),但具体还是根据题目意思而定

  4. 通过矩阵快速幂来优化乘法,得到最终矩阵并与初始矩阵相乘

然后就静候AC吧


__EOF__

本文作者hl666
本文链接https://www.cnblogs.com/cjjsb/p/9047769.html
关于博主:复活的ACM新生,目前爱好仅剩Gal/HBR/雀魂/单机/OSU
版权声明:转载请注明出处
声援博主:欢迎加QQ:2649020702来DD我
posted @   空気力学の詩  阅读(161)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示