[笔记] 矩阵
行列式
\(\det(A)=\sum_{\sigma\in S_n}\operatorname{sgn}(\sigma)\prod_{i=1}^na_{i,\sigma(i)}\)
其中 \(S_n\) 是指长度为 \(n\) 的全排列的集合,\(\sigma\) 就是一个全排列,如果 \(\sigma\) 的逆序对对数为偶数,则 \(\operatorname{sgn}(\sigma)\),否则 \(\operatorname{sgn}(\sigma)=-1\)
- 矩阵转置,行列式不变;
- 矩阵行(列)交换,行列式取反;
- 矩阵行(列)相加或相减,行列式不变;
- 矩阵行(列)所有元素同时乘以数 \(k\),行列式也乘 \(k\)。
行列式求值
- 如果不需要取模或者模数为质数,则直接高斯消元,否则辗转相除。
int det(){
int tg = 1, res = 1;
lfor(i, 1, n){
int k = i;
lfor(j, k + 1, n) if(a[j][i] > a[k][i]) k = j;
if(!a[k][i]) return 0;
if(i != k) swap(a[k], a[i]), tg = -tg;
lfor(j, i + 1, n){
while(a[j][i]){
int x = a[i][i] / a[j][i];
lfor(k, i, n) a[i][k] = (a[i][k] + 1LL * (p - x) * a[j][k]) % p;
swap(a[j], a[i]), tg = -tg;
}
}
res = 1LL * res * a[i][i] % p;
}
res *= tg; return (res + p) % p;
}
矩阵求逆
在高斯消元的同时对单位矩阵做同样的操作。
bool Inv(){
lfor(i, 1, n){
int k = i;
lfor(j, i + 1, n) if(a.a[j][i]){ k = j; break; }
if(!a.a[k][i]) return 0;
if(k != i) a.Swap(k, i), inv.Swap(k, i);
inv.mul(i, qpow(a[i][i])), a.mul(i, qpow(a[i][i]));
lfor(j, 1, n) if(i != j)
inv.add(j, i, mod - a[j][i]), a.add(j, i, mod - a[j][i]);
}
return 1;
}
积和式
\(\operatorname{perm}(A)=\sum_{\sigma\in S_n}\prod_{i=1}^na_{i,\sigma(i)}\)
- \(\bmod 2\) 意义下等于行列式。
矩阵的秩
\(\operatorname{rank}(A)=A\) 中能选出的最多的线性无关的行数。
如果某一行能被其它的行组合出来,则称他们线性相关。
LGV 引理
关键词:路径交点
- 矩阵 \(a_{i,j}\) 权值为第 \(i\) 个起点到第 \(j\) 个终点的路径条数,则 \(\det(A)\) 即为第 \(i\) 个起点到第 \(i\) 个终点,\(n\) 条路径无交点的方案数。
- 可能存在条件限制和变式。
矩阵乘法的常数优化
- 对于较小的矩阵,在运算需要取模是,可以使用 long long,在 \(O(n^3)\) 次乘法后进行 \(O(n^2)\) 的取模。
矩阵乘法的应用
- 加速递推;
- 加速 DP 转移;
- 有一些修改操作,用矩阵乘法可以很好地表达。