线性代数(应用篇)

高斯消元

用于求解线性方程组的一组解

int get_c(int r, int c) { // 找到第r行(含)以下不全为0的第c列(含)以后的第1列,并将其主元所在行换到第r行
    for (;c <= n + 1; c ++)
        for (int i = r; i <= n; i ++) if (b[i][c]) { // 将第i行和第r行对换
            for (int j = c; j <= n + 1; j ++) swap(b[i][j], b[r][j]);
            return c;
        }
    return n + 2;
}
int gauss() { // return:无解-1,无穷多解0,唯一解1
    int r, c;
    for (r = 1, c = get_c(r, 1); c <= n; c = get_c(++ r, ++ c)) { // r,c 分别表示当前要处理的行、列
        for (int j = n + 1; j >= c; j --) b[r][j] /= b[r][c]; // 归一化
        for (int j = 1; j <= n; j ++) if (j != r && b[j][c]) // 该行应该消
            for (int k = n + 1; k >= c; k --) b[j][k] -= b[r][k] * b[j][c];
    }
    return r == n + 1 ? 1 : (c == n + 1 ? -1 : 0);
}

求解行列式

也是消元, 为了精度, 用辗转相除法

int det (int a[][N]) {
	int res = 1, w = 1;
	for (int i = 1; i <= n; i++)
		for (int j = i + 1; j <= n; j++) {
			while (a[i][i]) {
				int div = a[j][i] / a[i][i];
				for (int k = i; k <= n; k++)
					a[j][k] = (a[j][k] - div * a[i][k] % mod + mod) % mod;
				std::swap(a[j], a[i]); w = -w;
			}
			std::swap(a[i], a[j]); w = -w;
		}
	for (int i = 1; i <= n; i++) res = res * a[i][i] % mod;
	res = res * w;
	return (res + mod) % mod;
}

LGV引理

用于求解有向无环图的带符号不交路径边权之积的和

假设有起点集合 \(S\) 终点集合 \(T\) 满足 \(\left| S \right| = \left| T \right|\)

我们设 \(w(P)\) 为路径 \(P\) 的路径边权积, 设 \(e (x, y)\)\(x\)\(y\) 的所有路径 \(w\) 之和

对于 \(a_{i, j} = e(i, j)\) 的矩阵求行列式就是带符号的不交路径边权之积的和

这个有符号题目中通常会表现为

求奇偶的差值

可以证明只有其中一种路径

随机赋权检验是否存在

线性基

直接 \(O(n log V)\) 做就可以

一些题目技巧

如何让线性基元素值最大, 贪心的从大到小加入就可以

前缀线性基

贪心的维护越靠后的越优

线性基求交

假设有向量组 \(V_1, V_2\) 他们的基底分别为 \(B_1, B_2\)

那么答案就是满足 \(B_1 \cup (B_2 / W)\) 线性无关, 且 \(W \subseteq V_1\) 的向量组 \(W\)

证明显然, 可以使用反证法

代码上我们可以不断插入 \(B_2\) 它就代表 \(V_2\) 然后尝试用 \(B_1 \cup (B_2 / W)\) 去表示它, 用 \(B_1\) 表示出来的插到 \(W\) 中, 不是的插入到 \(B_2 / W\) 就可以了


void merge (int a[64], int b[64], int g[64]) {
	int tmp[64], aa[64];
	for (int i = 0; i <= 63; i++)
		tmp[i] = a[i], aa[i] = a[i];
	int cur, d;
	for (int i = 0; i <= 63; i++) 
		if (b[i]) {
			cur = 0; d = b[i];
			for (int j = i; j >= 0; j--) 
				if (d >> j & 1) {
					if (tmp[j]) {
						d ^= tmp[j];
						cur ^= aa[j];
						if (d) continue;
						g[i] = cur; 
					} else tmp[j] = d, aa[j] = cur;
					break;	
				}
		}
}

复杂度是 \(O(log^2 V)\)

posted @ 2025-07-31 15:55  d3genera7e  阅读(2)  评论(0)    收藏  举报