线性基入门
线性基维护的是向量空间的一组基。在 OI 中,这种算法一般用来解决子集异或和类型的题目。
基本定义
容易发现,异或运算本身等价于在各数位上进行模二意义下的加法。
即每一个数位看作一维,每一个数都看作一个 \(n\) 维向量。
我们相当于求 \(\Z_2^n\) 的一组基。
首先定义什么是线性表示:
定义1:定义一整数集合(以下均指整数集合) \(S={x_1,x_2,\dots,x_n}\) 的异或和 \(\text{sum}(s):=x_1 \text{xor} x_2\dots\text{xor}x_n\) 。
即为所有数异或起来的结果。
注意到这里的“系数”只有零和一,所以异或就是这个线性空间里唯一的线性运算。
定义2:定义一个集合 \(S\) 的张成 \(\text{span}(S) = \{\text{sum}(T)\ |\ T \subseteq S\}\)。
\(S\) 的所有子集的异或和组成的集合。与原本的张成定义类似。
若对于集合 \(S\),\(0 \in \text{span}(S)\),则称集合 \(S\) 线性相关。反正,则称 \(S\) 线性无关。
就是如果 \(S\) 中有一个元素 \(S_i\) 能被表示为其余某些元素的异或和,则这个集合 \(S\) 线性相关。
线性基
我们称集合 \(B\) 是 \(S\) 的线性基,当且仅当 \(B\) 满足:
- \(\forall a\in S,a\in\text{span}(B)\)。
- \(B\) 是满足条件 1 的最小集合。
通俗来讲就是没有冗余的向量组。
构造方法
考虑高斯消元,显然可以直接求出基底。
高斯消元的过程相当于化成三角矩阵,那么我们只要类似的构造三角矩阵即可。
我们在进行高斯消元的时候,总是确定一个行向量,然后用其他行向量去减去这个行向量来进行加减消元。
那么我们这里就直接进行异或,把这一位异或掉即可。
具体来讲,我们定义数组 \(p\) 为集合 \(S\) 的线性基,其中 \(p_i\) 表示用来控制这一位为 1 的数。
考虑向 \(S\) 中加入一个数 \(x\)。从高到低考虑 \(x\) 的二进制的每一个为 1 的数位:
- 如果 \(p_i\) 不存在,说明之前的数无法使这一位为 1,直接令 \(p_i \leftarrow x\)。
- 否则,对 \(x\) 进行消元,令 \(x \leftarrow x \text{xor} p_i\)。
const int N = 105;
int n;
long long p[N], ans;
void ins(long long x) {
for (int i = 63; i>=0; i--) {
if (x >> i == 0) continue;
if (!p[i]) return p[i] = x, void();
x ^= p[i];
}
}
应用
查询一个数是否可被表示
与插入类似,直接进行消元,最终消成零就说明可被表示。
查询子集异或最大/小值
逐位考虑即可。假设消元是从大到小进行的:
对于最小值,由构造方法知道,\(p_i\) 即是可被表示的最高位为 1 的数。
找到存在的最低位的 \(p_i\),容易知道这个数是唯一的。因为如果存在两个最高位都为 \(i\) 的数 \(a,b\),那么 \(a \text{xor} b\) 的最高位必定比 \(i\) 小,矛盾。
所以最小值就是这个 \(p_i\)。
对于最大值,显然将所有存在的维度全部变成 1 是最大的。
查询第 \(k\) 小
注意到我们在查询最小值的时候利用了最低位的唯一性。
那么我们能否对线性基进行一下改造,使得其具有类似的“唯一”性质呢?
注意到,如果只使用 \(1,2,4,8\dots\) 这一类二的幂,是必定可以构造出一组基的,而且用这一组基来构造第 \(k\) 小的方法显而易见。
从高到低考虑每一位,将 \(p_i\) 异或上后面的某些 \(p_j\),使得 \(p_i\) 只有最高位为一即可。
举例:
110 011 001
变成
100 010 001
然后就是简单的构造。
查询排名
贰分。

浙公网安备 33010602011771号