矩阵加速递推与转移矩阵构造方法

一.前置芝士

1.矩阵乘法

最一般的矩阵乘法是一个 np 的矩阵,记为 A,和一个 pm 的矩阵,记为 B,相乘,乘出来是一个 nm 的矩阵,记为 C
用公式表达就是

Ci,j=k=1pAi,k+Bk,j

代码就直接模拟

貌似有时间复杂度为 O(nlog(7))矩阵乘

但貌似除了用来卡常并没有什么用

inline void mul(int A[N][P], int B[P][M], int C[N][M]){
    for(int i = 1; i <= N; i++)
        for(int j = 1; j <= M; j++)
           for(int k = 1; k <= P; k++)
               C[i][j] += A[i][k] * B[k][j];     
}

2.矩阵快速幂

求一个矩阵的N次方

这是一个求 abmodp 的程序

inline int fast_power(int a, int b, int p){
    int ret = 1;
    while(b){
        if(b & 1) ret = (ret * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ret;
}

那么对于一个矩阵求快速幂只要把上面的代码魔改一通就好了。

首先代码中的 ret 肯定不是 1 了,那么在矩阵乘法中的 "1" 是什么呢?

考虑如下的一个方阵 I (注意是方阵,是 nn 的矩阵)

I=[1000010000100001]

随便找几个矩阵和它相乘(如果能的话),会发现与它相乘的矩阵还是那个矩阵,没有变,所以这个矩阵就相当于 “1”。

把上面的两个代码结合起来就好了。代码就不放了

二.矩阵加速

1.基本原理

拿斐波那契数列来举例子

fi=fi1+fi2(i2,f1=1,f2=1)

现在要求这个序列的第 k 项。

我们把 fi1fi2 放入如下所示的一个矩阵A中(其实是个向量,这里把缺的补成一个方阵)

[fi1fi200]

然后我们就需要最重要的东西——转移矩阵了。

如果我们构造一个矩阵 B,使 AB 得到的矩阵为如下矩阵

[fifi100]

那么我们就可以一直乘上 B 得到的矩阵就是

[fi+1fi00]

[fi+2fi+100]

...

但我们只要求第 k 项,式子可以变成 ABk2 ,而
Bk2 可以用矩阵快速幂来快速求出。问题解决了。

2.转移矩阵的构造方法

乱搞

常规型

非常简单,每一项只跟前几项有关系。

先放一个矩阵加速入门题

根据题目给的递推式,我们很容易可以列出递推的矩阵。(就是上面的矩阵 A

[ax1ax2ax3000000]

这个矩阵中 ax1, ax2, ax3 的初值就是 a1, a2, a3

现在来推矩阵 B

AB 得到的矩阵 C 应该是

[axax1ax2000000]

已知 ax=ax1+ax3
所以这个新矩阵可以改成

[ax1+ax3ax1ax2000000]

根据矩阵乘法的公式可知

C1,1=A1,1B1,1+A1,2B2,1+A1,3B3,1

C1,2=A1,1B1,2+A1,2B2,2+A1,3B3,2

C1,3=A1,1B1,3+A1,2B2,3+A1,3B3,3

然后根据上面的式子可以凑出转移方程

其实还是很好凑的

找找规律,可以得出一条算阶上的结论

如果原矩阵的第 i 项会对转移后矩阵的第 j 项产生影响,那么就在转移矩阵的第 i 行第 j 列写上适当的常数。(可以结合这个例子理解一下)

含常数型

类似于这样的递推式

fi=fi1+fi2+k

把它塞到一个矩阵 A 里面

[fi1fi2k000000]

乘上转移矩阵 B 后应该得到这样的一个矩阵

[fifi1k000000]

发现常数项根本没变,就在原来的位置所以矩阵 B 的最后一列就是

[001]

所以这种形式的递推式常数直接搬到下一个矩阵就好了。

转移矩阵就是

[110100101]

总结一下,这种带常数的递推式直接把常数放到矩阵里,转移的时候直接搬到下一个矩阵就行了。

含未知数型

类似与这样的形式

fi=fi1+fi2+i

这个时候有点麻烦,不仅要推 fi, 还要推 i

这种情况中递推矩阵要同时递推 fii

要把 i 看成另一个递推式 gi 这样可能会好理解一点。

原式变成了这个样子

fi=fi1+fi2+gi

先推 gi,递推式显然

gi=gi1+1

那么这个递推式就是一个很简单的含常数型递推式,容易得出递推矩阵和转移矩阵

递推矩阵:

[gi1100]

转移矩阵:

[1011]

其实这两个矩阵做题时不用构造

现在构造 f 的递推矩阵

[fi1fi2gi1000000000000]

乘上转移矩阵之后应该是这个样子的

[fifi1gi+11000000000000]

fifi1, fi2, gi 的影响。

fi1 直接转移。(也可以说受 fi1 的影响)

gigi11 的影响。

1 直接转移。(受 1 的影响)

上面四句话“翻译”一下

新矩阵第 1 项受原矩阵第 123 项的影响

新矩阵第 2 项受原矩阵第 1 项的影响

新矩阵第 3 项受原矩阵第 34 项的影响

新矩阵第 4 项受原矩阵第 4 项的影响

之前说过

如果原矩阵的第 i 项会对转移后矩阵的第 j 项产生影响,那么就在转移矩阵的第 i 行第 j 列写上适当的常数

这句话改一下

如果新矩阵的第 j 项受原矩阵的第 i 的影响,那么就在转移矩阵的第 i 行第 j 列写上适当的常数

再根据上面翻译的四句话,很容易写出转移矩阵

[1100100010100011]

遇到难推的矩阵,可以用上面的方法去想。

再放一个比较难的递推式

fi=fi1+fi2+i2

和上面一样,设 gi=i2

这要递推 gi ,怎么推呢?

我们知道 (i1)2=i22i+1。那么i2=(i1)2+2i1

所以gi=gi1+2i1

那么要推出 gi,矩阵中就要保存 gi1i1

这个 i 也是要递推的,设 hi=i=hi1+1

递推矩阵是

[fi1fi2gihi100000000000000000000]

乘上转移矩阵后应得到

[fifi1gi+1hi+1100000000000000000000]

用之前的方法,转移矩阵也很好构造,注意 g
转移时,hi 的常数

[1100010000101000021000111]

貌似矩阵还能转移带 min/max 函数的。但本蒟蒻不会。就先放着

参考资料

算法竞赛进阶指南

辰星凌的博客QAQ

posted @   QAQfj5  阅读(141)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示