数学狗都不学

线性代数

线性基

  • 线性空间(人话):一组向量通过线性组合得到的向量所形成的空间。

  • 线性无关(人话):在一组线性无关的向量中,不能用多个向量通过线性组合表示出另一个向量。

  • 极大线性无关组:在一组向量中选一个最大的子集,这个子集中的向量线性无关。

  • 基:称线性空间 \(V\) 的一个极大线性无关组为 \(V\) 的一组 线性基,简称基。

OI 中常用的基是基于 Xor 运算的,首先一个数 \(a_i\) 可以看做一个值为 \(0/1\) 的列向量 \(\overrightarrow{a_i} = \begin{bmatrix}b_{i,1} \\\vdots \\b_{i,k}\end{bmatrix}\),那么一组数字的异或和就可以表示为一组列向量的线性组合:

\[\overrightarrow{S} = x_1\overrightarrow{a_1} \oplus x_2\overrightarrow{a_2} \dots \oplus x_n\overrightarrow{a_n} = x_1\begin{bmatrix}b_{1,1} \\\vdots \\b_{1,k}\end{bmatrix} \oplus x_2\begin{bmatrix}b_{2,1} \\\vdots \\b_{2,k}\end{bmatrix} \oplus \dots \oplus x_n\begin{bmatrix}b_{n,1} \\\vdots \\b_{n,k}\end{bmatrix} \]

所以最终异或和向量 \(\overrightarrow{S}\) 一定位于这些向量所张成的线性空间中,也就是由这一组向量的基的线性组合而构成。

问题转化为找一组向量的基。

加入:法一 高斯消元

对这组向量构成矩阵的转置矩阵 \(A^T\) 进行消元,最后得到的上三角矩阵转置回来就是一组基。

加入:法二 增量法

加入一个数 = 在高斯消元中加入一个行向量,从上往下暴力枚举行向量,如果新向量在这一行的主元列有值,接下来如果当前行没有主元,它就成为主元,反之就把两个向量 Xor 一下,消元。

单次插入 \(\mathcal{O}(\log n)\),代码如下:

点击查看代码
inline void add(int x) {
	for (int i = 29; i >= 0; --i) {
		if (!(x & (1 << i))) continue;
		if (!basic[i]) return void(basic[i] = x);
		else x ^= basic[i];
	}
}

删除操作

三种做法:

法一 线段树分治

  • 优点:不动脑子。
  • 缺点:多个 \(\log\)

法二 离线时间戳

类比 LCT 维护无向图连通性:贪心选择时间戳靠后的替换时间戳靠前的,这样子删除的时候一定是真正删除,不会出现有不在基中的数替代它成为新的基的情况。

每一个基维护一个加入时异或过它的基的集合,找到其中最后的一个,用它向上异或,抵消掉当前删除的基的影响即可。

  • 优点:快,好写。
  • 缺点:离线。

合并操作

合并就启发式合并就可以了,将小线性基往大线性基中暴力插入,\(O(\log^2 V)\)

事实上,由于线性基大小为 \(O(\log V)\),不用启发式也是可以的。

应用

异或最大值

按位贪心,当前这一位异或后会更大就异或。

\(k\) 大异或和

引入一个技巧,类比高斯约当消元法,将基消元为每一个主元列都只有主元行有值的矩阵。

此时 \(k\) 大异或和,按位处理,对于第 \(i\) 位,如果当前位 \(k\) 的值为 \(1\),则对应当前主元选择,反之对应当前主元不选择。这显然是正确的。

事实上,不用消元按位讨论也是可以的。

给定异或和排名

每一个异或和都会出现 \(2^{n-|S|}\) 次,\(|S|\) 是线性基大小。

按位处理,如果当前位有主元而且查询异或和 \(x\) 在当前位值为 \(1\),也就意味着如果这一位选择小的情况,那么这一位往后的所有有主元的位任意选择都为比 \(x\) 小,产生 \(2^{rnk_i-1}\) 的贡献,代码如下:

REP(i, 0, 29) pre[i] = pre[i - 1] + (basic[i] != 0); 
PER(i, 29, 0) if (basic[i] && (Q & (1 << i))) (Ans += qpow(2ll, pre[i] - 1)) %= P;

【例】LG4869 albus就是要第一个出场

区间线性基

使用线段树维护,启发式合并即可。

重点提一个技巧:当你有区间异或操作的时候,线性基不支持整体异或一个数,考虑差分转单修。

此时设差分数组为 \(b_i = a_i \oplus a_{i-1}\),显然有:\(a_i = b_1 \oplus b_2 \dots b_i\)

那么对于一组 \(a_{p_1} \oplus a_{p_2} \oplus \dots \oplus a_{p_n}\),我们把每个 \(a_i\) 都展开成 \(a_l \oplus b_{[l+1,i]}\) 的形式,暴力相消,最后一定等价于在 \(a_l\)\(b_{[l+1,r]}\) 中选择一组数的异或和。此时可以使用线段树维护线性基,快速查询。

【例】LG11620 [Ynoi Easy Round 2025] TEST_34

posted @ 2025-03-15 09:44  flowing_boat  阅读(22)  评论(0)    收藏  举报