线性代数基础 Linear Algebra Basics
线性代数基础 \(Linear Algebra Basics\)
向量
向量定义
一个 \(n\) 维向量 \(V\) 可以表示为:
\[V = (v_1, v_2, \dots, v_n)
\]
点积运算
两个 \(n\) 维向量 \(p\) 和 \(q\) 的点积:
\[p \cdot q = \sum_{i=1}^n p_i q_i
\]
示例:
\[\begin{aligned}
p &= (1, 2, 3) \\
q &= (4, 5, 6) \\
p \cdot q &= 1 \times 4 + 2 \times 5 + 3 \times 6 = 32
\end{aligned}
\]
矩阵
矩阵定义
一个 \(m \times n\) 的矩阵 \(A\):
\[A = \begin{pmatrix}
a_{11} & a_{12} & \cdots & a_{1n} \\
a_{21} & a_{22} & \cdots & a_{2n} \\
\vdots & \vdots & \ddots & \vdots \\
a_{m1} & a_{m2} & \cdots & a_{mn}
\end{pmatrix}
\]
特殊矩阵
单位矩阵 \(I_n\):
\[I_n = \begin{pmatrix}
1 & 0 & \cdots & 0 \\
0 & 1 & \cdots & 0 \\
\vdots & \vdots & \ddots & \vdots \\
0 & 0 & \cdots & 1
\end{pmatrix}
\]
矩阵运算
矩阵加法
\[(A + B)_{ij} = A_{ij} + B_{ij}
\]
矩阵数乘
\[(kA)_{ij} = k \cdot A_{ij}
\]
矩阵乘法
对于 \(A_{m \times n}\) 和 \(B_{n \times p}\):
\[(AB)_{ij} = \sum_{k=1}^n A_{ik} B_{kj}
\]
注意 : 矩阵乘法不满足交换律 !!!
再说一遍 :矩阵乘法不满足交换律 !!!
最后一遍 :矩阵乘法不满足交换律 !!!
示例:
\[\begin{pmatrix}
1 & 2 \\
3 & 4
\end{pmatrix}
\begin{pmatrix}
5 & 6 \\
7 & 8
\end{pmatrix}
=
\begin{pmatrix}
1 \times 5 + 2 \times 7 & 1 \times 6 + 2 \times 8 \\
3 \times 5 + 4 \times 7 & 3 \times 6 + 4 \times 8
\end{pmatrix}
=
\begin{pmatrix}
19 & 22 \\
43 & 50
\end{pmatrix}
\]
代码模板
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 500 + 5;
const int MOD = 1e9 + 7;
int n, p, m;
int A[N][N], B[N][N], C[N][N];
void read() {
cin >> n >> p >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= p; j++) {
cin >> A[i][j];
A[i][j] = (A[i][j] % MOD + MOD) % MOD;
}
}
for (int i = 1; i <= p; i++) {
for (int j = 1; j <= m; j++) {
cin >> B[i][j];
B[i][j] = (B[i][j] % MOD + MOD) % MOD;
}
}
}
void mul() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
ll sum = 0;
for (int k = 1; k <= p; k++) {
sum += (1ll * A[i][k] * B[k][j]) % MOD;
sum %= MOD;
}
C[i][j] = sum;
}
}
}
void print() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cout << C[i][j] << " ";
}
cout << "\n";
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
read();
mul();
print();
return 0;
}
矩阵转置
\[(A^T)_{ij} = A_{ji}
\]
矩阵快速幂
定义
对于方阵 \(A\):
\[A^k = \underbrace{A \times A \times \cdots \times A}_{k \text{次}}
\]
快速算法
利用二进制分解:
\[A^k = \prod_{i=0}^{\lfloor \log_2 k \rfloor} A^{2^i}
\]
代码模板
#include <bits/stdc++.h>
using namespace std;
const int N = 1e2 + 3;
const int MOD = 1e9 + 7;
struct Matrix {
int n;
int mat[N][N];
Matrix(int _n = 0) : n(_n) { memset(mat, 0, sizeof(mat)); }
void E() { for (int i = 1; i <= n; i ++) mat[i][i] = 1; }
};
Matrix mul(Matrix a, Matrix b) {
int n = a.n;
Matrix ret(n);
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
for (int k = 1; k <= n; k ++) {
ret.mat[i][j] = (ret.mat[i][j] + 1ll * a.mat[i][k] * b.mat[k][j]) % MOD;
}
}
}
return ret;
}
Matrix quick_pow(Matrix x, long long p) {
int n = x.n;
Matrix ret(n);
ret.E();
while (p) {
if (p & 1) ret = mul(ret, x);
x = mul(x, x);
p >>= 1;
}
return ret;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
long long k;
cin >> n >> k;
Matrix a(n);
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
cin >> a.mat[i][j];
a.mat[i][j] = (a.mat[i][j] % MOD + MOD) % MOD;
}
}
Matrix res = quick_pow(a, k);
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
cout << res.mat[i][j] << ' ';
}
cout << '\n';
}
return 0;
}
常系数齐次线性递推与矩阵加速 !!!
一、线性递推的数学本质
1. 递推关系的矩阵表示
对于k阶线性递推关系:
\[f_n = \sum_{i=1}^k c_i f_{n-i} \quad (n > k)
\]
存在转移矩阵 \(A\) 满足:
\[\underbrace{
\begin{bmatrix}
f_n \\
f_{n-1} \\
\vdots \\
f_{n-k+1}
\end{bmatrix}
}_{V_n}
= A \times
\underbrace{
\begin{bmatrix}
f_{n-1} \\
f_{n-2} \\
\vdots \\
f_{n-k}
\end{bmatrix}
}_{V_{n-1}}
\]
2. 转移矩阵的结构特性
矩阵 \(A\) 具有如下标准形式:! ! !
\[A = \begin{bmatrix}
c_1 & c_2 & \cdots & c_{k-1} & c_k \\
1 & 0 & \cdots & 0 & 0 \\
0 & 1 & \cdots & 0 & 0 \\
\vdots & \vdots & \ddots & \vdots & \vdots \\
0 & 0 & \cdots & 1 & 0
\end{bmatrix}_{k \times k}
\]
构造原理:
- 第一行:直接对应递推系数
- 次对角线:全1元素用于"移位"记录历史状态
二、矩阵加速的严格推导
1. 递推展开过程
通过递归展开可得:
\[V_n = A \times V_{n-1} = A^2 \times V_{n-2} = \cdots = A^{n-k} \times V_k
\]
其中初始向量:
\[V_k = \begin{bmatrix}
f_k \\
f_{k-1} \\
\vdots \\
f_1
\end{bmatrix}
\]
2. 时间复杂度分析
计算过程分为两步:
- 计算矩阵幂 \(A^{n-k}\):
- 使用快速幂算法
- 每次矩阵乘法 \(O(k^3)\) 时间
- 总时间 \(O(k^3 \log n)\)
- 矩阵-向量乘法:
- \(O(k^2)\) 时间
三、推广到非齐次情况
1. 含常数项的递推
对于递推式:
\[f_n = \sum_{i=1}^k c_i f_{n-i} + d
\]
构造技巧:
- 升维处理:\[\widetilde{V}_n = \begin{bmatrix} V_n \\ 1 \end{bmatrix} = \begin{bmatrix} f_n \\ \vdots \\ f_{n-k+1} \\ 1 \end{bmatrix} \]
- 扩展转移矩阵:\[\widetilde{A} = \begin{bmatrix} A & \begin{matrix} d \\ 0 \\ \vdots \\ 0 \end{matrix} \\ 0 \cdots 0 & 1 \end{bmatrix} \]
2. 含多项式项的递推
对于递推式:
\[f_n = \sum_{i=1}^k c_i f_{n-i} + P(m)
\]
其中 \(P(m)\) 是 \(m\) 次多项式
构造方法:
- 需要跟踪的变量:
- \(f_n\) 及其历史项
- \(m^j \ (j=0,1,...,m)\)
- 转移矩阵维度:
- 总维度 \(= k + (m + 1)\)
四、典型例题的解析理论
例题1:三阶递推问题
给定:
\[f_n = f_{n-1} + f_{n-3} \quad (n \geq 4)
\]
初始条件:\(f_1=f_2=f_3=1\)
矩阵构造过程
确定状态向量:
\[V_n = \begin{bmatrix}
f_n \\
f_{n-1} \\
f_{n-2}
\end{bmatrix}
\]
建立方程关系:
\[\begin{cases}
f_n = 1·f_{n-1} + 0·f_{n-2} + 1·f_{n-3} \\
f_{n-1} = 1·f_{n-1} + 0·f_{n-2} + 0·f_{n-3} \\
f_{n-2} = 0·f_{n-1} + 1·f_{n-2} + 0·f_{n-3}
\end{cases}
\]
得到转移矩阵:
\[A = \begin{bmatrix}
1 & 0 & 1 \\
1 & 0 & 0 \\
0 & 1 & 0
\end{bmatrix}
\]
求解步骤
计算幂次:
\[power = n - 3
\]
最终表达式:
\[\begin{bmatrix}
f_n \\
f_{n-1} \\
f_{n-2}
\end{bmatrix}
= A^{n-3} \times
\begin{bmatrix}
f_3 \\
f_2 \\
f_1
\end{bmatrix}
\]
五、理论边界与限制
1. 适用条件
- 必须严格满足线性关系
- 系数必须为常数(不能是 \(n\) 的函数)
2. 不适用情况
- 非线性递推:\[f_n = f_{n-1} \times f_{n-2} \]
- 变系数递推:\[f_n = n \cdot f_{n-1} \]
3. 维度爆炸问题
当递推式中包含:
- 多个多项式项
- 高次多项式时
会导致转移矩阵维度急剧增加,实际应用中需权衡:
\[\text{矩阵维度} = k + \sum_{i=1}^m (\deg(P_i) + 1)
\]
六、理论延伸
1. 与特征根法的联系
矩阵特征多项式:
\[\det(\lambda I - A) = 0
\]
正是递推关系的特征方程,二者通解形式一致。
2. 广义矩阵加速
对于分块矩阵情形,可处理:
- 多个相互关联的递推式
- 二维递推问题
- 带有模运算的特殊递推
代码模板
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 1e9 + 7;
const int N = 5;
struct Matrix {
int n;
int mat[N][N];
Matrix(int _n = 0) : n(_n) { memset(mat, 0, sizeof(mat)); }
void E() { for (int i = 1; i <= n; i++) mat[i][i] = 1; }
};
Matrix A(3), init(3);
void pre() {
A.mat[1][1] = 1;
A.mat[1][3] = 1;
A.mat[2][1] = 1;
A.mat[3][2] = 1;
init.mat[1][1] = 1;
init.mat[2][1] = 1;
init.mat[3][1] = 1;
}
Matrix mul(Matrix a, Matrix b) {
int n = a.n;
Matrix ret(n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
ret.mat[i][j] = (ret.mat[i][j] + 1ll * a.mat[i][k] * b.mat[k][j]) % MOD;
}
}
}
return ret;
}
Matrix quick_pow(Matrix x, ll p) {
int n = x.n;
Matrix ret(n);
ret.E();
while (p) {
if (p & 1) ret = mul(ret, x);
x = mul(x, x);
p >>= 1;
}
return ret;
}
void solve(int n) {
if (n <= 3) {
cout << "1\n";
return;
}
Matrix ret = quick_pow(A, n - 3);
Matrix ans = mul(ret, init);
cout << ans.mat[1][1] << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T; cin >> T;
pre();
while (T--) {
int n; cin >> n;
solve(n);
}
return 0;
}
线性方程组
增广矩阵表示
方程组:
\[\begin{cases}
a_{11}x_1 + a_{12}x_2 + \cdots + a_{1n}x_n = b_1 \\
a_{21}x_1 + a_{22}x_2 + \cdots + a_{2n}x_n = b_2 \\
\vdots \\
a_{m1}x_1 + a_{m2}x_2 + \cdots + a_{mn}x_n = b_m
\end{cases}
\]
增广矩阵:
\[\left(
\begin{array}{cccc|c}
a_{11} & a_{12} & \cdots & a_{1n} & b_1 \\
a_{21} & a_{22} & \cdots & a_{2n} & b_2 \\
\vdots & \vdots & \ddots & \vdots & \vdots \\
a_{m1} & a_{m2} & \cdots & a_{mn} & b_m
\end{array}
\right)
\]
高斯消元法
基本操作
- 交换两行
- 某行乘以非零常数
- 将某行的倍数加到另一行
消元步骤
- 化为上三角矩阵
- 回代求解
示例:
\[\begin{aligned}
&\left(
\begin{array}{ccc|c}
1 & 1 & 1 & 6 \\
2 & 1 & 1 & 10 \\
1 & 2 & 1 & 10
\end{array}
\right) \\
\rightarrow &\left(
\begin{array}{ccc|c}
1 & 1 & 1 & 6 \\
0 & -1 & -1 & -2 \\
0 & 1 & 0 & 4
\end{array}
\right) \\
\rightarrow &\left(
\begin{array}{ccc|c}
1 & 0 & 0 & 1 \\
0 & 1 & 0 & 4 \\
0 & 0 & 1 & -2
\end{array}
\right)
\end{aligned}
\]
解得:
\[x = 1, \quad y = 4, \quad z = -2
\]
代码模板
#include <bits/stdc++.h>
using namespace std;
const int N = 1e2 + 10;
int n;
double a[N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n + 1; j ++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i ++) {
int p = i;
while (p <= n && a[p][i] == 0) p ++;
if (p == n + 1) {
cout << "No Solution" << '\n';
return 0;
}
for (int j = 1; j <= n + 1; j ++)
swap(a[i][j], a[p][j]);
double tmp = a[i][i];
for (int j = 1; j <= n + 1; j ++)
a[i][j] /= tmp;
for (int j = 1; j <= n; j ++) {
if (i == j) continue;
tmp = a[j][i];
for (int k = 1; k <= n + 1; k ++) {
a[j][k] -= a[i][k] * tmp;
}
}
}
cout << fixed << setprecision(2);
for (int i = 1; i <= n; i ++)
cout << a[i][n + 1] << '\n';
return 0;
}
部分由 AI 润色
晨雾纸间
山中何事?松花酿酒,春水煎茶
文/lvwangshu·书于云深处
晨雾纸间
✦
原创·转载请注明出处
✦
浙公网安备 33010602011771号