P3390 【模板】矩阵快速幂
\(P3390\) 【模板】矩阵快速幂
一、矩阵乘法介绍
有两个矩阵:\(A\)和\(B\)(矩阵实际上就是二维数组)
\(A\)矩阵和\(B\)矩阵可以做乘法运算必须满足\(A\)矩阵的列的数量等于\(B\)矩阵的行的数量
运算规则:\(A\)的每一行中的数字对应乘以\(B\)的每一列的数字把结果相加起来
二、矩阵乘法模板
1641:【例 1】矩阵 A×B
用户名:littlehb 密码:md******22
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m, p;
int a[N][N], b[N][N], c[N][N];
//矩阵乘法模板
void mul(int a[][N], int b[][N], int c[][N]) {
//注意:这里的临时数组t绝不是画蛇添足!
//因为调用的时候,有时会传递mul(a,b,b)这样的东东,如果每次memset(c,0,sizeof c),
//就会造成b在运行前被清空,导致结果错误
int t[N][N] = {0};
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
for (int k = 0; k < N; k++)
t[i][j] = t[i][j] + a[i][k] * b[k][j]; //矩阵乘法
memcpy(c, t, sizeof t);
}
int main() {
cin >> n >> m;
// A矩阵 n*m
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
// B矩阵m*p
cin >> p;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= p; j++)
cin >> b[i][j];
//矩阵乘法
mul(a, b, c);
//输出结果,控制格式
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= p; j++)
printf("%d ", c[i][j]);
printf("\n");
}
return 0;
}
三、矩阵快速幂
单位矩阵
在普通的乘法中,一个数乘\(1\)还是等于它本身,在矩阵乘法中也有这么一个\(1\),它就是单位矩阵
不同于普通乘法中的单位\(1\),对于不同矩阵他们的单位矩阵大小是不同的
对于\(n∗m\)的矩阵,它的单位矩阵大小为\(m∗m\),对于\(m∗n\)的矩阵,它的单位矩阵大小为\(n∗n\)
也就是说单位矩阵都是正方形的,这是因为只有正方形的矩阵能保证结果和前一个矩阵形状相同
单位矩阵的元素非\(0\)即\(1\),从左上角到右下角的对角线上元素皆为\(1\),其他皆为\(0\)
使用单元矩阵
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 110;
LL n, k; //本题数据范围很大,用int直接wa哭了
LL a[N][N], b[N][N]; //原始矩阵,结果矩阵
//矩阵乘法模板
void mul(LL a[][N], LL b[][N], LL c[][N]) {
LL t[N][N] = {0};
for (LL i = 0; i < N; i++)
for (LL j = 0; j < N; j++)
for (LL k = 0; k < N; k++)
t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; //矩阵乘法
memcpy(c, t, sizeof t);
}
int main() {
cin >> n >> k;
//输入原始矩阵
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> a[i][j];
// 1、单位矩阵
for (int i = 0; i < n; i++) b[i][i] = 1;
// 2、矩阵快速幂
for (LL i = k; i; i >>= 1) {
if (i & 1) mul(a, b, b);
mul(a, a, a);
}
// 3、输出
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
printf("%lld ", b[i][j]);
printf("\n");
}
return 0;
}
不使用单元矩阵
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 110;
LL n, k; //本题数据范围很大,用int直接wa哭了
LL a[N][N], b[N][N]; //原始矩阵,结果矩阵
//矩阵乘法
void mul(LL a[][N], LL b[][N], LL c[][N]) {
LL t[N][N] = {0};
for (LL i = 0; i < N; i++)
for (LL j = 0; j < N; j++)
for (LL k = 0; k < N; k++)
t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; //矩阵乘法
memcpy(c, t, sizeof t);
}
int main() {
cin >> n >> k;
// 1、输入原始矩阵
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
cin >> a[i][j];
b[i][j] = a[i][j]; //这种解法与标准解法不同,不用构建单位矩阵
//直接赋值初始化了一个,然后执行k-1次就完成了矩阵的k次幂
}
// 2、计算矩阵快速幂
for (LL i = k - 1; i; i >>= 1) {
if (i & 1) mul(a, b, b);
mul(a, a, a);
}
// 3、输出
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
printf("%lld ", b[i][j]);
printf("\n");
}
return 0;
}