Loading

线性基入门

线性基维护的是向量空间的一组基。在 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\) 满足:

  1. \(\forall a\in S,a\in\text{span}(B)\)
  2. \(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

然后就是简单的构造。

查询排名

贰分。

posted @ 2021-03-12 20:20  LewisLi  阅读(115)  评论(0)    收藏  举报