\(P3390\) 【模板】矩阵快速幂
一、矩阵乘法介绍
有两个矩阵:\(A\)和\(B\)(矩阵实际上就是二维数组)
\(A\)矩阵和\(B\)矩阵可以做乘法运算必须满足\(A\)矩阵的列的数量等于\(B\)矩阵的行的数量
运算规则:\(A\)的每一行中的数字对应乘以\(B\)的每一列的数字把结果相加起来
二、矩阵乘法模板
1641:【例 1】矩阵 A×B
用户名:littlehb 密码:md******22
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 110;
int n, m, p;
int a[N][N], b[N][N], c[N][N];
//二维乘二维的矩阵乘法模板
void mul(int c[][N], int a[][N], int b[][N]) {
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] + (LL)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(c, a, b);
//输出结果,控制格式
for (int i = 1; i <= n; i++, puts("")) //好牛B的一个写法!
for (int j = 1; j <= p; j++)
printf("%d ", c[i][j]);
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 c[][N], LL a[][N], LL b[][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(b, b, a);
mul(a, a, a);
}
//输出
for (int i = 0; i < n; i++, puts(""))
for (int j = 0; j < n; j++)
printf("%lld ", b[i][j]);
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 c[][N], LL a[][N], LL b[][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];
b[i][j] = a[i][j]; //这种解法与标准解法不同,不用构建单位矩阵
//直接赋值初始化了一个,然后执行k-1次就完成了矩阵的k次幂
}
// 2、计算矩阵快速幂
for (LL i = k - 1; i; i >>= 1) {
if (i & 1) mul(b, b, a);
mul(a, a, a);
}
//输出
for (int i = 0; i < n; i++, puts(""))
for (int j = 0; j < n; j++)
printf("%lld ", b[i][j]);
return 0;
}