线性代数
矩阵
计算
加减法
将两个矩阵对应位置的元素相加减即可,两个矩阵的行,列数相等。
满足交换律 \(A + B = B + A\) 和结合律 \((A + B) + C = A + (B + C)\)。
乘法
-
一个数字 \(k\) 乘上矩阵 \(A\),把 \(A\) 中的所有元素都乘上 \(k\),记作 \(kA\)。
-
矩阵 \(A\) 乘上矩阵 \(B\),要求 \(A\) 的列数等于 \(B\) 的行数,若 \(A\) 是一个 \(n \times k\) 的矩阵,\(B\) 是一个 \(k \times m\) 的矩阵,那么乘积 \(C\) 的大小就是 \(n \times m\),\(C_{i, j} = \sum \limits _ {p = 1} ^ k A_{i, p} \times B_{p, j}\)。
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
for (int p = 1; p <= k; p++) {
c[i][j] += a[i][p] * b[p][j];
}
}
}
满足结合律 \((A \times B) \times C = A \times (B \times C)\),但是不满足交换律。
单位矩阵
单位矩阵就是一个从左到右的对角线上的元素为 \(1\),其他地方的元素都为 \(0\) 的矩阵。
快速幂
首先,如果一个矩阵 \(A\) 可以快速幂,那么这个矩阵必须是 \(n \times n\) 的,也就是说,必须行数和列数相等。
而在前面,我们已经学会了矩阵乘法了,所以,剩下的操作就和快速幂是一样的了。
快速幂如果不会可以看这里 数论。
struct matrix {
int m[N][N];
matrix operator * (const matrix &x) const {
matrix ret;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
ret.m[i][j] = 0;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
ret.m[i][j] = (ret.m[i][j] + 1ll * m[i][k] * x.m[k][j] % mod) % mod;
}
}
}
return ret;
}
} a;
matrix P(matrix a, long long b) {
matrix ret;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
ret.m[i][j] = 0;
}
ret.m[i][i] = 1;
}
while (b) {
if (b & 1) {
ret = ret * a;
}
a = a * a, b >>= 1;
}
return ret;
}
矩阵快速幂加速递推
洛谷 P1939
这道题给了一个递推式,但是 \(n\) 太大了,所以,我们可以考虑用矩阵快速幂加速递推。
首先,我们可以构造一个 \(1 \times 3\) 的矩阵 \(\begin{bmatrix} a_n, a_{n - 1}, a_{n - 2} \end{bmatrix}\),这个矩阵是由 \(\begin{bmatrix} a_{n - 1}, a_{n - 2}, a_{n - 3} \end{bmatrix}\) 乘上某个矩阵得到的,所以我们需要构造出这个加速递推的 \(3 \times 3\) 的矩阵 \(\begin{bmatrix} 1 & 1 & 0\\ 0 & 0 & 1 \\ 1 & 0 & 0 \end{bmatrix}\),再对这个矩阵做矩阵快速幂,最后输出即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 10, mod = 1e9 + 7;
int T, n;
struct matrix {
int m[N][N];
matrix operator * (const matrix &x) const {
matrix ret;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
ret.m[i][j] = 0;
}
}
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
for (int k = 1; k <= 3; k++) {
ret.m[i][j] = (ret.m[i][j] + 1ll * m[i][k] * x.m[k][j] % mod) % mod;
}
}
}
return ret;
}
} a, b;
matrix P(matrix a, int b) {
matrix ret;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
ret.m[i][j] = 0;
}
ret.m[i][i] = 1;
}
while (b) {
if (b & 1) {
ret = ret * a;
}
a = a * a, b >>= 1;
}
return ret;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> T;
while (T--) {
cin >> n;
a.m[1][1] = a.m[1][2] = a.m[2][3] = a.m[3][1] = 1, a.m[1][3] = a.m[2][1] = a.m[2][2] = a.m[3][2] = a.m[3][3] = 0;
if (n < 3) {
cout << 1 << '\n';
continue;
}
a = P(a, n - 3);
cout << ((a.m[1][1] + a.m[2][1]) % mod + a.m[3][1]) % mod << '\n';
}
return 0;
}
洛谷 P1349
这道题我们先构造一个 \(1 \times 2\) 的矩阵 \(\begin{bmatrix} a_n, a_{n - 1} \end{bmatrix}\),然后我们就可以构造出对应的 \(2 \times 2\) 的矩阵 \(\begin{bmatrix} p & 1 \\ q & 0 \end{bmatrix}\),再快速幂一下就可以了。
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int p, q, a1, a2, n, mod;
struct matrix {
int m[N][N];
matrix operator * (const matrix &x) const {
matrix ret;
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= 2; j++) {
ret.m[i][j] = 0;
}
}
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= 2; j++) {
for (int k = 1; k <= 2; k++) {
ret.m[i][j] = (ret.m[i][j] + 1ll * m[i][k] * x.m[k][j] % mod) % mod;
}
}
}
return ret;
}
} a, b;
matrix P(matrix a, long long b) {
matrix ret;
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= 2; j++) {
ret.m[i][j] = 0;
}
ret.m[i][i] = 1;
}
while (b) {
if (b & 1) {
ret = ret * a;
}
a = a * a, b >>= 1;
}
return ret;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> p >> q >> a1 >> a2 >> n >> mod;
a.m[1][1] = p, a.m[1][2] = 1, a.m[2][1] = q, a.m[2][2] = 0;
if (n == 1) {
cout << a1;
return 0;
}
a = P(a, n - 2);
cout << (1ll * a.m[1][1] * a2 % mod + 1ll * a.m[2][1] * a1 % mod) % mod;
return 0;
}