Basis
线性基是向量空间的一组基,通常可以解决有关异或的一些题目。
通俗一点的讲法就是由一个集合构造出来的另一个集合,它有以下几个性质:
-
线性基的元素能相互异或得到原集合的元素的所有相互异或得到的值。
-
线性基是满足性质 1 的最小的集合。
-
线性基没有异或和为 0 的子集。
-
线性基中每个元素的异或方案唯一,也就是说,线性基中不同的异或组合异或出的数都是不一样的。
-
线性基中每个元素的二进制最高位互不相同。
构造线性基的方法如下:
对原集合的每个数 p 转为二进制,从高位向低位扫,对于第 $x$ 位是 1 的,如果 $a_x$ 不存在,那么令 $a_x=p$ 并结束扫描,如果存在,令 $p=p~\text{xor}~a_x$。
代码:
inline void insert(long long x) {
for (int i = 55; i + 1; i--) {
if (!(x >> i)) // x的第i位是0
continue;
if (!p[i]) {
p[i] = x;
break;
}
x ^= p[i];
}
}
查询原集合内任意几个元素 xor 的最大值,就可以用线性基解决。
将线性基从高位向低位扫,若 xor 上当前扫到的 $a_x$ 答案变大,就把答案异或上 $a_x$。
为什么能行呢?因为从高往低位扫,若当前扫到第 $i$ 位,意味着可以保证答案的第 $i$ 位为 1,且后面没有机会改变第 $i$ 位。
查询原集合内任意几个元素 xor 的最小值,就是线性基集合所有元素中最小的那个。
查询某个数是否能被异或出来,类似于插入,如果最后插入的数 $p$ 被异或成了 0,则能被异或出来。