最近写了四篇创作计划了,我太高产了
今天我们要讲解的是一种冷门但实用的算法——矩阵快速幂
注意:本篇文章的前置知识是矩阵乘法,碍于时间所限,不做具体讲解
目录
1. 简介
2. 核心思想
3. 使用条件
4. 代码流程
5. 典例分析
6. 进阶应用
7. 例题
Part 1. 简介
矩阵快速幂是一种强大的算法,其主要作用是将O(n)的线性dp优化为O(logn)的快速幂
Part 2. 核心思想
矩阵快速幂的核心思想是:将递推关系表示为矩阵形式,然后利用矩阵乘法的结合律,通过快速幂算法快速计算矩阵的高次幂,从而直接得到递推式第 n 项的值。
Part 3. 使用条件
注意!这个条件肥肠重要!
满足以下条件的 dp 通常可以用矩阵快速幂优化:
-
状态转移是线性的:即 dp[i] 可以由前面若干个 dp[j] 的线性组合得到。
-
递推系数是常数:不随 i 的变化而变化。
-
递推阶数固定:即dp[i]只依赖于前面固定k个状态,如dp[i−1],dp[i−2],…dp[i−k]。
Part 4. 代码流程
假设现在我们要优化这个柿子:
dp[n]=a1⋅dp[n−1]+a2⋅dp[n−2]+⋯+ak⋅dp[n−k]
需要几步呢?总共分三步:
1. 构造状态向量
我们构造一个包含当前 k 个状态的状态向量:
Vn=dp[n]dp[n−1]⋮dp[n−k+1]
我们的目标是从 Vn−1推出Vn。
2. 构造转移矩阵
我们需要找到一个 k×k 的矩阵 M,使得:
Vn=M⋅Vn−1
根据递推关系:
- 第一行:dp[n]=a1⋅dp[n−1]+a2⋅dp[n−2]+⋯+ak⋅dp[n−k]
⇒矩阵第一行为[a1,a2,…,ak]
- 第二行:dp[n−1]=1⋅dp[n−1]+0⋅dp[n−2]+0⋅…
⇒矩阵第二行为[1,0,…,0]
- 第三行:dp[n−2]=0⋅dp[n−1]+1⋅dp[n−2]+0⋅…
⇒矩阵第三行为[0,1,…,0]
于是,转移矩阵为:
M=a110⋮00a201⋮00a300⋱……………⋮10ak−100⋮01ak00⋮00
3. 矩阵快速幂
我们有:
Vn=M⋅Vn−1=M2⋅Vn−2=⋯=Mn−k+1⋅Vk−1
其中Vk−1是初始向量,即已知条件。
于是我们直接使用快速幂计算Mn−k+1(时间O(k3logn)),然后乘以初始向量 Vk−1得到 Vn,其第一个元素就是 dp[n]。
Part 5.典例分析
我们观察斐波那契数列,他的递推式是:
Fn=Fn−1+Fn−2,F0=0,F1=1
先构造向量:
Vn=[FnFn−1]
得到矩阵(中间我们跳一步):
M=[1110]
验证一下:
Vn=M⋅Vn−1⟹[FnFn−1]=[1110][Fn−1Fn−2]
初始条件:
V1=[F1F0]=[10]
所以:
Vn=Mn−1⋅V1
于是我们就求出了斐波那契数列
Part 6.进阶应用
举个更复杂的例子:带前 k 项和的递推,例如:
dp[n]=dp[n−1]+dp[n−2]+sum[n−1]
其中
sum[n]=sum[n−1]+dp[n]
此时我们构造的向量我们需要包含三个状态:
Vn=dp[n]dp[n−1]sum[n]
构造方程:
dp[n]=dp[n−1]+dp[n−2]+sum[n−1]dp[n−1]=1⋅dp[n−1]+0⋅dp[n−2]+0⋅sum[n−1]
以及:
sum[n]=sum[n−1]+dp[n]=sum[n−1]+(dp[n−1]+dp[n−2]+sum[n−1])=dp[n−1]+dp[n−2]+2⋅sum[n−1]
整理得到矩阵:
M=111101102
验证:
Vn⇓dp[n]dp[n−1]sum[n]=M⋅Vn−1=111101102dp[n−1]dp[n−2]sum[n−1]
于是这个问题就解决了。
Part 7. 例题
以上两题均为模板题,不做讲解
看似含参,但也不难 还怪押韵,由读者自行完成
这是最近我写的第四篇创作计划,打字不易,点个赞吧!@AC君求精
有帮助,赞一个