线性基小结
线性基是用来处理异或和的一大利器,对于一个数集\(S\),它的线性基是一个最小的集合\(S_1\),使得\(S\)内元素异或得到的值的值域与\(S_1\)内元素的值的异或得到的值的值域相同
很明显一个序列的线性基具有如下的性质:集合内元素相互异或得到的值不可能为0
证明:反证法,假设存在\(a_1,a_2,\cdots,a_p\)使得\(a1\ xor\ a2\ xor \cdots \ xor\ a_p=0\)
由异或的性质就可以得到\(a_1=a_2\ xor \cdots \ xor \ a_p\)
对于某一个数\(x=a_1 \ xor\ y\),如果\(y\)能被该线性基用异或表示,那么将\(a_1\)与\(y\)异或在一起来表示\(x\)的话,无论怎么样都不会用到\(a_1\)
即存在一个更小的线性基\([a_2,a_3,\cdots,a_n]\),\(a_1\)是无用的,这与线性基的定义相矛盾,原命题得证
由上面的性质你可以得到如下推论:如果某个数\(x\)可以被这个线性基表示出来,那么这个表达方式唯一(证明也可以使用反证法)
构造
对于一个给定的序列,如何构造它的线性基呢?
我们记原来的序列为\(a_1,a_2,\cdots,a_n\),它的线性基为\(p_1,p_2,\cdots,p_m\)(其中\(m\)为\(a_i\)中的数在二进制表示下的最大位数)
同时我们规定,\(p_i\)的二进制表示中最高位是第\(i\)位且这一位为1
也就是说,对于一个\(p_i\)只会有
1)若\(p_i=0\),则只有可能在满足\(j>i\)的\(p_j\)的二进制表示的第\(i\)上出现1
2)若\(p_i\not=0\),那么\(p_i\)中比第\(i\)位更高的位上一定是0,但比第\(i\)为更低的位上有可能出现1;并且对于所有的\(j>i\)中\(p_j\)中的第\(i\)位上一定是0
流程的话我们考虑每一次\(insert\)一个数
假设当前\(insert\)的数是\(x\),我们从高位向低位枚举,如果当前\(x\)的最高位对应的线性基\(p_i\)为0,那么就令\(p_i=x\)并且结束;否则就令\(x=x\ xor \ p_i\)并且继续枚举
这样做显然不会破坏之前出现的值域,并且当我们考虑由这个数与其他数组成的新的异或值,由上面的操作我们知道\(x\)是可以被线性基中的某些数得到的,所以我也可以用这些数与其他数组合来得到新的异或值(即由操作过程我们是有\(x=p_{i_1}\ xor\ p_{i_2}\ xor \cdots xor\ p_{i_k}\)的)
合并
合并操作类似于插入操作,将线性基\(A\)中的所有元素依次插入线性基\(B\)中即可
查询
一般的查询就是询问一个数\(x\)能否被当前的线性基表示出来
这个问题与插入十分相似,对\(x\)的最高位逐步考虑即可
从线性基的最高位开始往下遍历,如果当前位\(L\)是\(x\)的最高非0二进制位,则令\(x=x\ xor \ p_L\),一直到遍历完成,如果此时\(x\)为0则该数可以被表示出来,反之则不可(其实本质就是贪心,考虑必须要将当前的最高位消去即可证明)
应用
比较经典的就是查询某个数集内的最大(小)异或和
建出线性基之后考虑贪心,从高到低遍历线性基,如果当前取这一位对答案有贡献就取(可以从当前线性基的最高位对答案影响开始考虑,如果取当前的线性基的话,有构造可知对后续的线性基是否选取也会有影响)
最小异或和的话直接取最小的非\(0\)的\(p_i\)即可(妈耶还是贪心)