行列式

命题1:将一个长度为 \(n\) 的排列的两个元素的位置进行交换(称作一次对换),逆序对的奇偶性会改变。可以通过构造 \(2x+1\) 次相邻两个位置的元素的交换来证明,其中 \(x\) 表示要交换的两个元素中间的元素个数,从左到右交换一遍,从右到左交换一遍。也可以通过分类讨论来证明。

定义1:

\[det(A)=|A|=\sum_{p}(-1)^{τ(p)} \prod_{i=1}^{n}a_{i,p_{i}} \]

其中 \(p\)\(1,2,\dots,n\) 的一个排列。\(τ(p)\) 是这个排列(逆序对)的奇偶性。

在定义中每项的 \(n\) 个元素的行指标是按照自然序排好位置 \(a_{1,j_{1}},a_{2,j_{2}},\dots a_{n,j_{n}}\),如果将这 \(n\) 个元素按任意顺序排好位置 \(a_{i_{1},k_{1}},a_{i_{2},k_{2}},\dots a_{i_{k},k_{n}}\),那么此时的符号如何确定呢?考虑对 \(i_{1},i_{2},\dots,i_{n}\) 的奇偶性进行分类讨论(利用命题 \(1\) 的结论来判断 \(j_{1},j_{2},\dots,j_{n}\)\(k_{1},k_{2},\dots,k_{n}\) 的奇偶性的关系),不难归纳出

\[(-1)^{τ(j)} a_{1,j_{1}} \times a_{2,j_{2}} \times... \times a_{n,j_{n}}= (-1)^{τ(i)+τ(k)} a_{i_{1},k_{1}} \times a_{i_{2},k_{2}} \times...\times a_{i_{n},k_{n}} \]

因此可以发现,当将每项的 \(n\) 个元素的指标按照自然序排好位置时,得到的结果也等于 \(|A|\)

命题2:当对矩阵的某一行乘上 \(k\) 后,得到的行列式是原行列式的 \(k\) 倍;当将两个除某行外全部相等的两个矩阵相加后得到的行列式为原来两个矩阵的行列式之和(能有这么长都是懒得打 Latex 导致的)。证明显然。

命题3:将矩阵的两行交换后得到的行列式是原来的相反数。设交换的是 \(x,y\) 这两行,原矩阵的两个元素 \(a_{x,i},a_{y,j}\) 在被交换后,根据命题 \(1\)\(p\) 的奇偶性会发生改变,所以符号相反。

命题4:如果矩阵存在两行成比例,那么其行列式为 \(0\)。只需要证明如果矩阵存在两行相等,那么其行列式为 \(0\)。由命题 \(3\)\(det(A)=-det(A)\),所以 \(det(A)=0\)

命题5:对一个矩阵的某一行加上另外一行乘上某个数,行列式不变。通过命题 \(2\) 和命题 \(4\) 可以证明。

根据 高斯消元 相关知识,我们知道任意一个矩阵都可以通过初等行变换化成阶梯形矩阵,归纳一下三种初等行变换对行列式的影响。

  • 某行加上另外一行的某个倍数:行列式不变。
  • 交换任意两行:行列式变成原来的相反数。
  • 用一个非零数 \(k\) 乘上某一行:行列式变为原来的 \(k\) 倍。

但是这道 模板题 需要将行列式的值对 \(P\) 取模,且 \(P\) 不一定是个质数,这意味着我们只能使用第一种和第二种初等行变换,这是因为第三种会使行列式变为原来的 \(k\) 倍,需要将最后的答案除以 \(k\),但 \(k\) 不一定有逆元。

考虑将两行进行辗转相减,使得第 \(a_{i,j}=0\),依次对每行进行操作即可。时间复杂度 \(O(n^2 \log n+n^3)\)。代码实现如下:

应用 LGV 引理 _

#include<bits/stdc++.h>
#define int long long
#define N 610
using namespace std;

int n, mod;
int a[N][N];

void work() {
	int x = 1, ans = 1;
	for(int i = 1; i <= n; i++) {
		for(int j = i + 1; j <= n; j++) {
			while(a[i][i]) {
				int Num = a[j][i] / a[i][i];
				for(int k = i; k <= n; k++) a[j][k] = (a[j][k] - Num * a[i][k] % mod + mod) % mod;
				swap(a[i], a[j]); ans = -ans;
			} 
			swap(a[i], a[j]); ans = -ans;
		}
	}
	
	
	/*for(int i = 1; i <= n; i++) {
		for(int j = 1; j <i; j++) if(a[i][j]) cout << a[i][j] << " ";
	}*/
	
	for(int i = 1; i <= n; i++) ans = ans * a[i][i] % mod;
	ans = (ans * x + mod) % mod;
	cout << ans;
}
signed main() {
	//freopen("P7112_1.in", "r", stdin);
	//freopen("x.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	cin >> n >> mod;
	for(int i = 1; i <= n; i++)
	for(int j = 1; j <= n; j++) cin >> a[i][j], a[i][j] %= mod;

	work();
	return 0;
}
posted @ 2024-07-15 21:04  小超手123  阅读(87)  评论(0)    收藏  举报