矩阵快速幂学习笔记

矩阵快速幂学习笔记

首先我们得先知道什么是快速幂

这里简要提一下,就是求 an 次方时,我们可以把 n 拆分成二进制(假设为 .....0110),然后就相当于求 ax+ay......a4+a2

然后矩阵快速幂就是对一个矩阵做快速幂,好像是废话

其实矩阵快速幂的实现非常简单,就是将快速幂中的乘法变为矩阵乘法即可,这里重点讲用矩阵快速幂优化递推。

模板:

vector<vector<LL>> mul(vector<vector<LL>> a, vector<vector<LL>> b, LL mod) { vector<vector<LL>> res(a.size(), vector<LL>(b[0].size(), 0)); int n = a.size(), m = b[0].size(), x = b.size(); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) for (int k = 0; k < x; k++) res[i][j] = (res[i][j] + a[i][k] * b[k][j] % mod) % mod; return res; } vector<vector<LL>> qmi(vector<vector<LL>> a, LL k, LL mod) { vector<vector<LL>> I = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; while (k) { if (k & 1) I = mul(I, a, mod); a = mul(a, a, mod); k >>= 1; } return I; }

直接看例题:

P1962 斐波那契数列

易得答案矩阵为 [fnfn1]

然后 fn 是从 [fn1fn2] 根据矩阵乘法的性质,递推矩阵为 [1110], 因为 fn=fn1+fn2

那么现在我们知道 [f2f1] 就要将乘法进行 n2 次,用矩阵快速幂优化。

所以递推式子就为:

[1110]n2[f2f1]

#include <algorithm> #include <cstring> #include <iostream> #include <vector> using namespace std; typedef long long LL; typedef pair<int, int> PII; const LL mod = 1e9 + 7; inline LL read() { LL x = 0, f = 1; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -f; s = getchar(); } while (s >= '0' && s <= '9') { x = (x << 3) + (x << 1) + (s ^ 48); s = getchar(); } return x * f; } //矩阵乘法 vector<vector<LL>> mul(vector<vector<LL>> A, vector<vector<LL>> B, LL MOD) { vector<vector<LL>> res(A.size(), vector<LL>(B[0].size(), 0)); int n = A.size(), m = B[0].size(), x = B.size(); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) for (int k = 0; k < x; k++) res[i][j] = (res[i][j] + A[i][k] * B[k][j] % MOD) % MOD; return res; } //矩阵快速幂 vector<vector<LL>> qmi(vector<vector<LL>> A, LL k, LL MOD) { //初始化单位矩阵 int n = A.size(); vector<vector<LL>> I(n, vector<LL>(n, 0)); for (int i = 0; i < n; i++) I[i][i] = 1; while (k) { if (k & 1) I = mul(I, A, MOD); A = mul(A, A, MOD); k >>= 1; } return I; } int main() { LL n; n = read(); if (n <= 2) { cout << '1'; return 0; } vector<vector<LL>> A{{1, 1}, {1, 0}}; //递推矩阵 vector<vector<LL>> f3{{1}, {1}}; auto M = qmi(A, n - 2, mod); auto fn = mul(M, f3, mod); cout << fn[0][0] << endl; return 0; }

P1939 【模板】矩阵加速(数列)

易得答案矩阵为 [fn fn1 fn2]

然后 fn 是从推出来的 [fn1fn2fn3] 根据矩阵乘法的性质,递推矩阵为 [101100010], 因为 fn=fn1+fn3

那么现在我们知道 [f3f2f1] 就要将乘法进行 n3 次,用矩阵快速幂优化。

所以递推式子就为:

[101100010]n3[f3f2f1]

#include <algorithm> #include <cstring> #include <iostream> #include <vector> using namespace std; typedef long long LL; typedef pair<int, int> PII; const LL mod = 1e9 + 7; inline int read() { int x = 0, f = 1; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -f; s = getchar(); } while (s >= '0' && s <= '9') { x = (x << 3) + (x << 1) + (s ^ 48); s = getchar(); } return x * f; } vector<vector<LL>> mul(vector<vector<LL>> a, vector<vector<LL>> b, LL mod) { vector<vector<LL>> res(a.size(), vector<LL>(b[0].size(), 0)); int n = a.size(), m = b[0].size(), x = b.size(); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) for (int k = 0; k < x; k++) res[i][j] = (res[i][j] + a[i][k] * b[k][j] % mod) % mod; return res; } vector<vector<LL>> qmi(vector<vector<LL>> a, LL k, LL mod) { vector<vector<LL>> I = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; while (k) { if (k & 1) I = mul(I, a, mod); a = mul(a, a, mod); k >>= 1; } return I; } int main() { int q; cin >> q; while (q -- ) { LL n = read(); if (n <= 3) { cout << 1 << endl; continue; } vector<vector<LL>> a = {{1, 0, 1}, {1, 0, 0}, {0, 1, 0}}; vector<vector<LL>> f3 = {{1}, {1}, {1}}; vector<vector<LL>> M = qmi(a, n - 3, mod); auto ans = mul(M, f3, mod); cout << ans[0][0] << endl; } return 0; }

__EOF__

本文作者ljfyyds
本文链接https://www.cnblogs.com/ljfyyds/p/16684379.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   ljfyyds  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示