线性基
线性基
纯 oi 讲解,可以当作数据结构来看,涉及到了 0 个线代。
定义
对于原集合或序列 \(a\),我们定义集合 \(s\) 为其线性基,那么 \(s\) 中的数应满足下面性质:
- \(s\) 中的数亦或不出来 \(0\)。
- \(s\) 可以亦或出 \(a\) 能亦或出的所有数,不能亦或出 \(a\) 亦或不出来的数。
- 线性基具有唯一性,对于能亦或出的数字 \(x\),设 \(t \subset s\) 中所有数亦或和为 \(x\),那么 \(t\) 是唯一的。
可以证明线性基只有 \(\log V\) 个元素,其中 \(V\) 表示值域。
构造
先说每个位置的意义。我们用 \(c_i\) 表示线性基中的每一个数字。第 \(i\) 位表示基中最高位为 \(i\) 的数,没有则为 \(0\)。
线性基支持动态的插入,不支持删除。对于我们插入了一个 \(x\),从高往低枚举位 \(i\)。若此时 \(x\) 最高位就为 \(i\),若 \(c_i = 0\) 则 \(c_i \gets x\),否则 \(x \gets x \oplus c_i\)。写成代码长这样:
void ins(int x) {
for(int i = maxk - 1; i + 1; i--) {
if((x >> i) & 1) {
if(c[i]) x ^= c[i];
else {
c[i] = x;
AC;
}
}
}
}
特殊的,当枚举完了之后 \(x = 0\),那么证明 \(x\) 能被亦或出来,我们称其为插入失败。
我们想建出集合 \(a\) 的线性基,只需要将其中元素一个一个插入即可。
运用
十分灵活。
- 对于集合 \(a\),快速判断其内部元素能否亦或出 \(x\)。
首先对 \(a\) 建出线性基 \(s\),然后从高到低位枚举 \(i\)。若当 \(x\) 最高位就是 \(i\),那么 \(x \gets c_i\)。枚举完之后,若 \(x = 0\) 那么 \(x\) 就能被亦或出来,\(x \ne 0\) 反之。
- 对于数字 \(x\),求其和任意若干个 \(a\) 中的数亦或后的最大值。
建出线性基,从高到低枚举位数。加入当前位数为 \(i\),若 \(x \oplus c_i > x\) 那么 \(x \gets c_i \oplus x\)。弄完之后的 \(x\) 就是答案。
- 线性基能异或出的最小值。
最小的 \(c_i \ne 0\)。
- 原序列能异或出的最小值
若出现插入失败则为 \(0\),否则还是最小的 \(c_i \ne 0\)。
- 对于集合 \(a\),求其所有能亦或出来的数之和。
拆贡献到每一位。先建出线性基。设 \(t\) 表示有多少个 \(c_i \ne 0\)。那么对于每一个有 \(c_i \ne 0\) 的 \(i\),都有贡献 \(2 ^ i \times 2 ^ {t - 1}\),总结一下答案为:
- 套线段树。
具体可以看这道题。

浙公网安备 33010602011771号