题解:P3390 【模板】矩阵快速幂 & 矩阵快速幂加速递推的应用思路
1.题解:P3201 [HNOI2009] 梦幻布丁2.题解:P7020 [NWRRC2017] Boolean Satisfiability3.题解:P6614 蛋糕 Cake4.题解:UVA10503 The dominoes solitaire5.题解:AT_abc383_c [ABC383C] Humidifier 36.题解:AT_abc266_c [ABC266C] Convex Quadrilateral7.题解:AT_abc296_e [ABC296E] Transition Game8.题解:CF350C Bombs9.题解:B3832 [NICA #2] 回来吧我的小波10.题解:B3803 [NICA #1] 上大分11.题解:AT_abc236_f [ABC236F] Spices12.题解:CF626B Cards13.题解:CF603A Alternative Thinking14.题解:CF917A The Monster15.题解:CF1540A Great Graphs16.题解:AT_arc008_3 [ARC008C] THE☆たこ焼き祭り201217.题解:P6606 [Code+#7] 最小路径串18.题解:P2422 良好的感觉19.题解:P2032 扫描20.题解:P1160 队列安排21.题解:ABC395(A-E)22.题解:P3865 【模板】ST 表 && RMQ 问题23.题解:P2590 [ZJOI2008] 树的统计24.答案:牛客周赛 Round 83(A-E)25.题解:U540617 捡松果
26.题解:P3390 【模板】矩阵快速幂 & 矩阵快速幂加速递推的应用思路
27.题解:P11848 [TOIP 2023] 房屋推荐28.题解:P2146 [NOI2015] 软件包管理器前置知识
今天把矩阵快速幂又复习了一遍,来博客上水一篇题解吧。
总而言之,矩阵快速幂 = 矩阵乘法 + 快速幂。
那矩阵乘法是什么呢?
设有两个矩阵
其中:
是矩阵 中第 行第 列的元素。 是矩阵 中第 行第 列的元素。 是矩阵 中第 行第 列的元素。 是矩阵 的列数(也是矩阵 的行数)。
注意,我们有一点非常重要,我们能否把
因此:
代码模板:
void mx(int a[N][N], int b[N][N], int n) { memset(tmp, 0, sizeof(tmp)); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { for (int k = 1; k <= n; k++) { tmp[i][j] += a[i][k] * b[k][j]; tmp[i][j] %= m; } } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { a[i][j] = tmp[i][j]; } } }
快速幂:
用于快速计算
oiwiki直链:https://oiwiki.com/math/binary-exponentiation/
代码模板:
ll qp(ll a,ll b,ll m){ ll res = 1; a %= m; while(b > 0){ if(b & 1)res = res * a % m; a = a * a % m; b >>= 1; } return res; }
解题思路
就是算
AC代码
#include <bits/stdc++.h> #define debug(a) cout << #a << "=" << a << '\n'; #define il inline #define int long long using namespace std; using ll = long long; using ull = unsigned long long; const int N = 110; int a[N][N], res[N][N], tmp[N][N], m, n,b; void mx(int a[N][N], int b[N][N], int n) { memset(tmp, 0, sizeof(tmp)); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { for (int k = 1; k <= n; k++) { tmp[i][j] = (tmp[i][j] + (1LL * a[i][k] * b[k][j]) % m) % m; // 使用 1LL 以防止溢出 } } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { a[i][j] = tmp[i][j]; } } } void qp(int a[N][N], int b, int m) { memset(res, 0, sizeof(res)); for (int i = 1; i <= n; i++) res[i][i] = 1; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { a[i][j] %= m; } } while (b > 0) { if (b & 1) mx(res, a, n); mx(a, a, n); b >>= 1; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { a[i][j] = res[i][j]; } } } signed main() { ios::sync_with_stdio(0), cout.tie(0), cin.tie(0); cin >> n >> b; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cin >> a[i][j]; } } m = 1e9 + 7; qp(a, b, m); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cout << a[i][j] << ' '; } cout << '\n'; } return 0; }
矩阵快速幂加速递推的思路
所谓矩阵加速递推实际上是使用矩阵快速幂这一快速计算矩阵幂次的工具来简化运算,并且简化的是求有彼此有相关关系的数列的运算,如斐波那契额数列的第n项求解(且n往往极大,按照数列表面的数学关系直接递推计算几乎不可能得到)等等;计算这样的递推次数很多的式子,我们需要一个更简化更快捷的计算方式,也就是矩阵快速幂。
首先我们需要想办法把实际问题转换为矩阵的形式来表示,这也是矩阵加速递推最关键的步骤。
例题:斐波那契数列。
其递推关系是:
根据其递推关系我们考虑将矩阵初始值设置为一个行向量(也可以理解成1x2的矩阵,其实列向量还是行向量都可以,只要转移矩阵也是对应的即可)。
构造一个
我们想要通过乘以转移矩阵,得到数列的下一项,也就是说:
我们把矩阵乘法展开,得到,
根据数列原本的关系
那么根据转移矩阵表现出来的与原数列的关系,我们可以这样来看,
由此我们就可以解决这个问题了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现