本文部分内容来自《高等代数》。
对于一个 n 阶行列式
An×n=∣∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋱⋮an1an2⋯ann∣∣
∣
∣
∣
∣∣
其结果为所有不同行不同列的元素乘积的代数和。用数学语言写为:
∑j1j2⋯jn(−1)τ(j1j2⋯jn)a1j1a2j2⋯anjn
其中 j1j2⋯jn 为 1∼n 的一个排列。τ(j1j2⋯jn) 表示排列 j 的逆序数的个数。
可以看出,如果 τ(j1∼jn) 为偶数,那么该排列对答案的贡献为正。否则为负。
《高代》里原本有七条性质,这里只证明有用的五条。
∣∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋱⋮an1an2⋯ann∣∣
∣
∣
∣
∣∣=∣∣
∣
∣
∣
∣∣a11a21⋯an1a12a22⋯an2⋮⋮⋱⋮a1na2n⋯ann∣∣
∣
∣
∣
∣∣
∣∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮kai1kai2⋯kainan1an2⋯ann∣∣
∣
∣
∣
∣
∣∣=k∣∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮ai1ai2⋯ainan1an2⋯ann∣∣
∣
∣
∣
∣
∣∣
首先考虑 n 级行列式的 n! 项。如果把他们分成 n 组,一定有一种方案,使得第 1 组中都含有 ai1,第 2 组中都含有 ai2,以此类推。如果第 j 项提出 aij 后记作 Aij,那么有
∣∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮an1an2⋯ann∣∣
∣
∣
∣∣
=ai1Ai1+ai2Ai2+⋯+ainAin=n∑j=1aijAij
这将方便我们后面的讨论。
现在证明性质二:
∣∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮kai1kai2⋯kainan1an2⋯ann∣∣
∣
∣
∣
∣
∣∣
=kai1Ai1+kai2Ai2+⋯+kainAin
=k(ai1Ai1+ai2Ai2+⋯+ainAin)
=k∣∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮ai1ai2⋯ainan1an2⋯ann∣∣
∣
∣
∣
∣
∣∣
∣∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮b1+c1b2+c2⋯bn+cnan1an2⋯ann∣∣
∣
∣
∣
∣
∣∣
=∣∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮b1b2⋯bnan1an2⋯ann∣∣
∣
∣
∣
∣
∣∣+∣∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮c1c2⋯cnan1an2⋯ann∣∣
∣
∣
∣
∣
∣∣
原行列式可写成 (b1+c1)Ai1+(b2+c2)Ai2+⋯+(bn+cn)Ain,这等于右式。
- 性质四:把第 k 行的倍数加到第 i 行,行列式不变。
证明太容易而公式又太难打,就不写了。
∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮ai1ai2⋯ain⋮⋮⋮ak1ak2⋯akn⋮⋮⋮an1an2⋯ann∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣
=∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮ai1+ak1ai2+ak2⋯ain+akn⋮⋮⋮ak1ak2⋯akn⋮⋮⋮an1an2⋯ann∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣
=∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮ai1+ak1ai2+ak2⋯ain+akn⋮⋮⋮−ai1−ai2⋯−ain⋮⋮⋮an1an2⋯ann∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣
=∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮ak1ak2⋯akn⋮⋮⋮−ai1−ai2⋯−ain⋮⋮⋮an1an2⋯ann∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣
=−∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣a11a12⋯a1na21a22⋯a2n⋮⋮⋮ak1ak2⋯akn⋮⋮⋮ai1ai2⋯ain⋮⋮⋮an1an2⋯ann∣∣
∣
∣
∣
∣
∣
∣
∣
∣
∣
∣∣
其中第一步是利用性质四,将第 k 行加到了第 i 行上。
第二步是利用性质四,将第 i 行减去第 k 行。
第三步是利用性质四,将第 i 行加到了第 k 行上。
最后一步是利用性质二,将第 i 行提出 −1。
证毕。
- 对角行列式
形如
∣∣
∣
∣
∣
∣∣a110⋯00a22⋯0⋮⋮⋱⋮00⋯ann∣∣
∣
∣
∣
∣∣
的行列式称为对角行列式。其结果为 a11×a22⋯ann。
- 三角行列式
形如 ∣∣
∣
∣
∣∣a11a12⋯a1n0a22⋯a2n⋮⋮⋮000ann∣∣
∣
∣
∣∣ 的行列式被称为三角行列式,其结果与对角行列式相同。
显然,如果按照定义,我们需要 O(n×n!) 的复杂度。显然无法接受。
由于存在一些特殊的行列式,可以考虑将原行列式转化为三角行列式后求值。思路就是将原行列式利用性质一到四进行转化。
例如有行列式 ∣∣
∣∣235347432∣∣
∣∣,首先可以将 2∼3 行分别加上第一行的 −32,−2 倍,化为 ∣∣
∣
∣
∣∣2350−12−120−3−8∣∣
∣
∣
∣∣。
接下来,把第三行加上第二行的 −6 倍,可得 ∣∣
∣
∣
∣∣2350−12−1200−5∣∣
∣
∣
∣∣。
于是原式化为了一个三角行列式。对角线乘积即为答案 5。
这个方法类似高斯消元的过程。因此就把它叫做高斯消元吧。
可以看出,这个方法的时间复杂度是 O(n3) 的,完全可以接受。
如果带模数怎么算行列式的值呢?
有一种方法叫做辗转相减法,可以完美的解决这个问题。
比如有行列式 ∣∣∣3241∣∣∣,首先先用第二行的第一个数除以第一行第一个数,得到 1。(这里是下取整)。
然后用第二行减去第一行 ×1,得到 ∣∣∣321−1∣∣∣。
容易证明第二行第一个数在操作完之后一定小于第一行第一个数。因此交换 1,2 行,得到 −∣∣∣1−132∣∣∣。
重复上述操作,直到第一行为 0。得到这样的行列式:∣∣∣051−1∣∣∣。
最后再把一、二行交换即可得到下三角行列式:
−∣∣∣1−105∣∣∣
答案即为 −5。
由于在辗转相减的过程中可以取模,所以这个问题就被完美解决了。
分析一下复杂度。易证辗转相减的复杂度与欧几里得算法类似,为 O(logn) 级别。如果记交换两行复杂度为 O(n),那么总复杂度就为 O(n2(logn+n))。
注意:两行交换时千万别忘变号!!!
#include <algorithm>
#include <cstdio>
#define int long long
using namespace std;
const int N = 610;
int n, p, w[N][N], f;
void Swap(int &a, int &b) {
for (int i = 1; i <= n; i ++ )
swap(w[a][i], w[b][i]);
f ^= 1;
}
int gauss() {
for (int i = 1; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ ) {
while (w[i][i]) {
int K = (int)w[j][i] / w[i][i];
for (int k = i; k <= n; k ++ )
((w[j][k] -= K * w[i][k] % p) += p) %= p;
Swap(i, j);
} Swap(i, j);
}
int ans = 1;
for (int i = 1; i <= n; i ++ )
(ans *= w[i][i]) %= p;
return (f ? (-ans + p) % p : (ans + p) % p);
}
signed main() {
scanf("%lld%lld", &n, &p);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
scanf("%lld", &w[i][j]);
return 0 & printf("%lld\n", gauss());;
}
本文公式很多,可能有笔误。希望大家可以指出。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库