线性代数(1):高斯消元与行列式
参考了 Little09 老师的课件和 cmd 大神的
矩阵
大家都会矩阵乘法,要注意矩阵乘法也关于加法具有结合律,但是不具有交换律喔!后面忘了。
高斯消元
和矩阵的关系
对于一个 \(n\) 元一次方程组我们至少需要 \(n\) 个方程才能解出来。
方程组写成 \(\begin{cases}a_{1,1}x_1+a_{1, 2}x_2+\dots + a_{1, n}x_n = b_1\\ a_{2,1}x_1+a_{2, 2}x_2+\dots + a_{2, n}x_n = b_2\\ \dots \\ a_{n,1}x_1+a_{n, 2}x_2+\dots + a_{n, n}x_n = b_n\\ \end{cases}\)
看作一个 \(n\times n\) 矩阵和 \(n\times 1\) 向量相乘的结果,那么就有
不过为了方便我们还是选择合并 \(a\) 和 \(b\) 的矩阵,也就是说
过程
大概就是我们小学的时候学习的解方程而已。
- 对于第 \(x_i\),找到一行满足 \(x_i\) 的系数不为 \(0\)。将此行与第 \(i\) 行交换。
- 将这一行全部除以 \(a_{i, i}\)。
- 对于它剩下所有行都通过第 \(i\) 行乘上 \(a_{j, i}\) 再减去消元。
最后会得到一个上三角矩阵。得到了很多形如 \(ax_i = b_i\) 的式子。
- \(b_i = 0\)
- \(a = 0\),那么无穷组解。
- \(a \not= 0\),那么无解。
细节
- 对于 \(x_i\),找行的时候,对于 \(j < i\),如果 \(a_{j, j} = 0\) 说明这一行还没有用,所以可以用来消元。
应用与拓展
异或方程组
如 P2447。
对于若干异或方程组,找到不为 \(0\) 的位置异或上去就好了,这个过程实际上可以用 bitset 优化从而做到 \(O(\dfrac{n^3}{w})\)
本题中直接二分再判定是 \(O(\dfrac{n^3}{w}\log m)\) 的显然过不去。回到高斯消元上面来。对于第 \(i\) 行,首先拿前 \((i - 1)\) 行的主元分别消掉,然后再考虑当前行的主元。如果所有主元都已经确定那么就跳掉回代。
时间复杂度就是 \(O(\dfrac{mn^2}{w})\) 的了。
有后效性 dp
P3232
我一开始想的是对于每条边的期望直接 dp,这当然是有问题的,对于边界条件是到 \(n\) 停下来,但是我们却无法确定到 \(n\) 前一条边的期望。
所以我们还是得从点考虑,\(f_u\) 为 \(u\) 点期望经过次数,对于所有边 \((v, u)\),都应该有 \(f_u = \sum\limits_{v}\dfrac{f_v}{deg_v}\)。特别的,\(u=1\) 时要额外 \(+1\),同时 \(v = n\) 不能计算。因为非 DAG,不能 topo 排序求解。必须高斯消元。
对于边 \((u, v)\) 经过次数期望应为 \(\dfrac{f_u}{deg_u}+\dfrac{f_v}{deg_v}\),按照此排序即可。
矩阵求逆
如何求解方程 \(AA^{-1} = I\)?
注意到这个和上面的线性方程组很相似,只要把 \(A^{-1}\) 每一行都看作一个行向量的话问题只不过从解未知数变成解向量了。这很明显也是一个道理,只要对左边的 \(A\) 消元成单位矩阵即可。
实现上就是说 \(A\) 和 \(I\) 拼接在一起对 \(A\) 做高斯消元。
你发现这个东西不是 \(I\) 也行,反正就是最后消元要把左边系数矩阵消元变成 \(I\)。
行列式
等等当当,终于到了线性代数最有炫酷的部分!
定义
行列式这样定义:
其中 \(P\) 为一个 \(n\) 的全排列,\(\mu(P)\) 与 \(P\) 的逆序对数量。也记作 \(\begin{vmatrix}A\end{vmatrix}\)
乘和式这样定义
初等行列变换
-
交换两行/两列,行列式取反。
-
对于某行/某列数乘 \(t\),行列式也乘 \(t\)。
-
对于 \(\begin{vmatrix}a & b \\ c & d\end{vmatrix} + \begin{vmatrix}a'&b'\\ c & d\end{vmatrix} = \begin{vmatrix}a+a'&b+b'\\c&d\end{vmatrix}\)
- 后面乘法分配律一下即可(
-
存在完全相等的两行,行列式为 0
- 利用第一条性质,交换两行,行列式取反但是又不能改变所以为 \(0\)。
-
某行加上另外一行的数乘 \(t\),行列式不变
- 利用第一条性质和第二条性质,得到如果存在一行为另一行数乘 \(t\),那么此行列式为 \(0\)。
- 把“加上另一行的数乘”写成第三个形式即可。
求解行列式
高斯消元的过程中行列式只会做简单的操作。
记录影响高斯消元成单位矩阵后计算乘积就好了。
如果模数为质数,那么就可以 \(O(n^3)\) 高斯消元了。但是可能不是质数。此时对于主元 \(i\) 的两个系数 \(a, b\) 辗转相除直到一方为 \(0\)。这个时间复杂度为 \(O(n^2\log V+ n^3)\),因为势能一直在减小,所以是 \(O(n^2\log V)\)
ll sol() {
ll rest = 1;
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
while(mat[i][i]) {
ll div = mat[j][i] / mat[i][i];
for(int k = i; k <= n; k++)
mat[j][k] = (mat[j][k] - div * mat[i][k] % Mod + Mod) % Mod;
swap(mat[j], mat[i]), rest = Mod - rest;
}
swap(mat[j], mat[i]), rest = Mod - rest;
}
}
ll mul = 1;
for(int i = 1; i <= n; i++)
mul = mul * mat[i][i] % Mod;
return mul * rest % Mod;
}
行列式性质
- \(\det(AB) = \det(A)\det(B)\)
- \(\bmod 2\) 意义下行列式积和式相等,可以看作对于二分图完美匹配计数的数量 \(\bmod 2\)(感觉会有不怀好意的出题人要出题了 QAQ)
矩阵树定理
给定一张图,求生成树数量。
无向图
定义 Laplace 矩阵 \(L\) 为度数矩阵 \(D\) 减去邻接矩阵 \(A\),也就是说对于边 \((x, y)\) 会让 \(L_{x, y}, L_{y, y}\) 增加 \(1\),\(L_{x, y}, L_{y, x}\) 减小 \(1\)。
去掉 Laplace 矩阵任意第 \(k\) 行第 \(k\) 列后求解行列式即生成树数量。
特别的,如果有边权,一个生成树权为边权乘积,那么直接把权看作重边即可。
有向图
只需要更改 \(D\) 定义即可,外向树 \(D\) 为入度矩阵,内向树 \(D\) 为初度矩阵。
例题
P3317
对于一棵生成树 \(S\) 里面的边贡献 \(p\),外面的边贡献 \((1 - p)\)。此时我们无法利用任何容斥手法。所以我们对每条边计算贡献,注意到只计算生成树出现的概率很好算,难以计算的点在没有被算入生成树时 \((1 - p)\) 的贡献。
这怎么办?
对于生成树 \(T\),贡献为 \(\prod\limits_{e\in T}p_e\prod\limits_{e\in (U - T)}(1-p_e)\)。遇到这个很显然我们会选择一个单步容斥(单步容斥也算容斥 111)求全集除以 \(T\),也就是 \(\dfrac{\prod_{e\in U}(1 - p_e)}{\prod_{e\in T}\frac{1 - p_e}{p_e}}\)。这样就成功独立贡献了.
格外注意 \(p_e = 1\) 时要将 \(p_e\) 减去 \(eps\)。被此肘击了。
P6624
显然的容斥,考虑 \(d|\gcd\) 那么只有 \(d|w_i\) 的边可能产生贡献,容斥系数为 \(\varphi(d)\)(这个地方卡了我很久,我一直在想 \(mu(d)\) 状物……糖丸了推导应该是 \(Id = 1* \varphi\))。问题在于对一张图求生成树权和,生成树权为边权和。
然后是一个非常牛的操作啊,看成一个 ogf,边权为 \((1+cx)\),乘积中 \(x\) 的一次项即为权和。多项式在模 \(x^2\) 意义下运算。也就是说我们目前要处理的矩阵每一个元素形如 \((c+dx)\)。
我们需要定义四则运算:
- \((a, b)+(c, d) = (a+c, b+d)\)
- \((a, b)\times (c, d) = (ac, cb + ad)\)
现在我们需要构造 \((a, b)\) 的逆元,对于 \((1, 0)\) 可以看作是单位元,那么 \((a^{-1}, -b)\) 可以看作是 \((a, b)\) 的逆元。
于是四则运算规定完毕就可以做了。
Gym104725C
直接 Matrix-Tree?不太可能。考虑加快求解这个行列式。
如何刻画补图?度数矩阵都变为 \(D_{i, i}\gets nk - 1 -D_{i, i}\),邻接矩阵 \(A_{i, j}\gets 1 - A_{i, j}\),特别的一开始我们认为也有 \(A_{i, i}\) 的连边。
一张矩阵上只存在 \(-1, 0\) 和对角线上的度数。对角线上的度数周期循环。再观察一下,主对角线上每个 \(n\times n\) 矩阵不变,外面全是 \(-1\),重复 \(k\) 次。考虑如何快速计算这个东西的行列式。
接下来我就没有想到了。感觉很牛逼。
我甚至连正确性都没完全搞懂,发怒,咕咕咕。
BEST 定理
给定一张欧拉图,求不同的欧拉回路数量。循环同构的欧拉回路被认为是一个。
大概的思路是对于一个欧拉回路保留每个点最后一条出边,形成一颗内向树,其它出边随意,所以是
\(k\) 为以 \(G\) 为根的生成树数量,因为欧拉图中入度等于出度,所以内向外向不重要。
对于以 \(k\) 为起点,那么 \(k\) 就没有出边,那么是 \(deg_kS\)。需要特判 \(k\) 度数为 \(0\) 情况。
牛客 矩阵与排列
考虑矩阵乘法的一个组合意义:\(A_{i,j }\) 看作图上 \(i\) 到 \(j\) 的路径数量,那么问题就变成了:给定一张 \(3\) 个点的图,边有颜色,问有多少从 \(1\) 开始的长度为 \(n\) 的回路满足颜色不同。
这个我会考虑容斥,\(n=40\) 并且无法二项式反演可以不用考虑容斥。
考虑确定一些东西。确定了顺序实际上是在增加约束,不好,所以考虑确定走的 \(n\) 条边,其中矩阵的值是系数,只需要统计这张图中的以 \(1\) 起点的欧拉回路数量作为第二个系数即可。
一开始我想的是记录整个 Laplace 矩阵然后 dp,然后就爆炸了,因为这个东西 \(3\times 3\),手法好一点注意到对角线上面(也就是自环)对 Laplace 矩阵无影响只用记录剩下 6 个元素,但是接下来 6 个元素就必须全部记录了(欧拉图要在最后判定)然后我就彻底不会了。
正解没有用到矩阵树定理。而是直接统计生成树数量。
注意到树的形态是相当少的,只有 \(8\) 种,单独压缩出来即可。\(f[i, d1, o1, d2, o2, w]\) 中 \(d1, o1, d2, o2\) 记录 \(1,2\) 的入度和出度,\(w\) 代表生成树的形态。直接转移即可,毫无手法。注意要卡常,循环展开一下 \(O(n^5)\) 大常数跑进 900ms,但是无法战胜叶哥,yzc2005Orz
贴个代码
LGV 引理
给定一张 DAG,其中有 \(m\) 个起点 \(A_1\sim A_m\),\(m\) 个终点 \(B_1\sim B_m\),求路径组权和,使得 \(A_i\) 可以到达 \(B_i\),且这些路径之间两两不交。一个路径组的权定义为每条边的权相乘。
结论:令 \(e(x, y)\) 为 \(x\) 到 \(y\) 所有路径的权和,那么定义矩阵
那么 \(\det A\) 即所求。
证明?感性理解:若 \(A_i\) 到 \(B_{\pi(i)}\) 和 \(A_j\) 到 \(B_{\pi_{j}}\) 中间有一个权交于点 \(u\),那么在交换第 \(i, j\) 位置中的新排列 \(\pi'\) 中会抵消。
`

浙公网安备 33010602011771号