线性基:处理异或操作的强大工具,思想也是可以借鉴的。
作用:用于处理多个数中选取一些数的XOR的最大值,最小值,第k大值,并可以查询能否通过集合中任意个数XOR得到,时间复杂度为O(n*logn)
线性基可以有多个,但是每个内部一定都是线性无关的,也就是说对于一个可以用线性基表示的x来说, 其组成方案一定是唯一的, 所以一个线性基的任意子集都不会构造出0.
构造线性基的核心就是 : 对于一个基 a,b, 我们可以用 a^b 替换任意一个,且不会影响这个基本身. 有了这个我们才可以很巧妙地构造线性基,且可以在这个基础上按照一定规则进行一些操作可以让这个线性基的性质更加的好看
思考
- 原集合能够亦或出0 ? 如果原集合的大小等于线性基的大小, 那么肯定不能够亦或出0, 因为线性基的任意子集都不会被亦或出0, 如果不等于, 那么原数组中多余的数都可以被线性基表示, 然后这两者亦或一定为0。
- 原集合的亦或第k小 ? 记ai为线性基中最高位的1在第i位的 向量, 可以按照i从大到小的顺序,用ai去异或aj (j>i).
这样最后得到的重塑后向量组又多了一个优美的性质: 只有ai的第i位是1,其他的第i位都是0. 有了这个性质,就容易证明要求第k小的异或和,只要把k二进制拆分,线性基中第j位是1就异或第j个线性基中的向量。正确性,我们脑补一下, 因为这样 重塑之后, 假设线性基的大小为sz, 那么从最低位到最高位就可以完全控制最后亦或值的大小,那么他可以组合出方案数为(1 << sz) - 1 个,并且按照二进制枚举的方式越来越大.还是无法说明白,QAQ
例题1 筱玛爱游戏
题意:两个人轮流从集合A中选择一个元素放进元素B里,如果放进集合B中的元素是的集合B存在一个子集异或为0,则会输掉比赛,问你先手赢还是后手。
思路:子集异或和不为零不就是线性基吗,遍历所有的数字,一个一个插入线性基里,判断能插入的个数的奇偶就行了。
bool Insert(ll x)
{
for(int i=63;i>=0;i--)//从最高位开始判断
{
if(x&(