专栏文章
P3390 题解
P3390题解参与者 3已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @mipgzqld
- 此快照首次捕获于
- 2025/12/03 11:51 3 个月前
- 此快照最后确认于
- 2025/12/03 11:51 3 个月前
传送门:P3390 【模板】矩阵快速幂
更佳的阅读体验:洛谷 P3390 题解
算法介绍
给你一个 的矩阵 ,现在你需要计算 (即 )。
当 时,你知道可以直接将两个矩阵 相乘得到答案。
当 时,你知道可以通过手写循环语句来计算最后的答案。
那么,当 呢?显然朴素的循环已经无法满足我们对程序的效率的要求,我们需要一个更快的算法。
陷入迷茫时,不妨回顾矩阵乘法的基本性质:
- 矩阵乘法满足结合律,即 。
此时想到,是否可以使用快速幂来优化算法?答案是肯定的。
与朴素的快速幂相同,对于矩阵快速幂,我们有:
此时,问题也就迎刃而解了。
值得注意的是,在进行幂运算之前,我们需要将结果矩阵初始化为单位矩阵,即:
这样才能保证矩阵快速幂的正确性。
复杂度分析
对于任意两个 的矩阵,相乘的时间复杂度为 。快速幂的复杂度为 。
因此,矩阵快速幂的时间复杂度为 ,可以通过本题。
代码实现
为了提高代码的可读性,我们将矩阵封装到结构体内,并且在结构体内重载乘运算符。
CPP#include <iostream>
using namespace std;
using ll = long long;
const int N = 110, MOD = 1e9 + 7;
int n;
ll k;
struct mat {
ll m[N][N], h, w;
void clear() {
h = w = n;
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j) m[i][j] = 0;
} void reset() {
clear();
for (int i = 1; i <= n; ++i) m[i][i] = 1;
} mat operator *(const mat &x) const {
mat res;
res.clear();
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= x.w; ++j)
for (int k = 1; k <= w; ++k)
res.m[i][j] = (res.m[i][j] + m[i][k] * x.m[k][j]) % MOD;
return res;
}
} a;
mat expow(mat a, ll b) {
mat res;
res.reset(), res.h = res.w = n;
while (b) {
if (b & 1) res = res * a;
a = a * a, b >>= 1;
} return res;
}
int main() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
cin >> n >> k, a.h = a.w = n;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) cin >> a.m[i][j];
a = expow(a, k);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) cout << a.m[i][j] << " \n"[j == n];
return 0;
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...