线性基
定义
张成
一个集合 的所有非空子集的异或和所组成的集合为 的张成,记作 。
线性相关 & 线性无关
如果一个集合 存在一个元素 使得 去掉 之后形成的集合 满足 ,则称 线性相关。
其实就是 存在一个元素可以由其它几个元素异或得到,而且从这可以知道,去掉一个线性相关的集合 里像 一样的元素后, 的张成不变。
反之,则称集合 线性无关。
线性基
我们称 是 的线性基,当且仅当:
- ;
- 线性无关。
性质
的线性基 有两个基本性质:
-
不存在一个真子集 使得 是 的线性基。
因为 线性无关,所以无法去掉 的任意元素使得 的张成不变。
-
的每个元素都可以被唯一表示为 的若干元素的异或和。
首先因为 ,所以 的每个元素都可以被表示为 的若干元素的异或和。
接下来使用反证法证明这个表示是唯一的。
假设 中一个元素 等于 的子集 的异或和,也等于子集 的异或和,且 和 没有交集。( 和 的公共部分是没有意义的)
然后 中的一个元素 可以被自己异或得到,也可以被 里的剩余元素和 的所有元素异或而成,这不满足 的线性无关性。
构造
我们使用一个数组 存储线性基,当 时我们称第 位存在。
这样构造出来的线性基有一个有用的限制:每个元素最高位互不相同。
我们考虑将数一个一个插入线性基。
根据线性基的性质, 个元素中,只要有一个元素第 位为 ,第 位就存在。所以如果数据随机,线性基的大小就比较大,这个性质有时候会应用。
插入过程
设插入的数为 ,考虑从高位考虑到低位,假设现在考虑到第 位。
- 如果 的第 位为 ,直接进入下一位的考虑即可。
- 否则:
- 如果第 位存在,我们需要将 的第 位消除,(因为只有 的第 位为 )把 异或上 即可。
- 如果第 位不存在,我们将 插入 。
如果 自始至终都没有被插入,那就说明 可以被线性基里的一些数异或出来,如果插入就不满足线性无关性。
证明
因为我们对 以及 的操作都是互相异或,这些操作显然是可逆的,所以用 的一些元素的异或和可以表示出原本的 。
代码
void insert(ll x){
for (int i = 49;i >= 0;i --){
if (x >> i & 1 ^ 1) continue;
if (b[i]) x ^= b[i]; // 用 b[i] 消去 x 的第 i 位
else { // 可以插入
b[i] = x; // 插入
break; // 一定不要忘记
}
}
// 如果没被插入(即 x 被异或成 0)就说明不需要 x
}
应用
子集最大异或和
令答案为 ,初始为 ,然后我们考虑倒序枚举位 ,如果 ,就令 等于 ,因为根据特殊性质,以后就没有改变 的第 位的机会。
子集最小异或和
根据根据特殊性质,答案为 的最小值。
子集 小异或和
如果数全都被插进线性基,选出线性基的一个非空子集有 种方案。
否则,有异或和为 的情况,一共有 种方案,如果 为 ,输出 即可,否则令 减 (去掉异或和为 的情况)。
令答案为 ,初始为 ,然后我们考虑 的每一个二进制位,假设考虑到第 位:
-
令 。
-
如果该位为 ,那么令 为 。
-
否则令 为 。