给出几个数,让您从中任选几个数使得它们的异或和最大,或者求出第 K 小异或和。这就需要线性基来处理。
引入
线性基就是一个容器。我们设这个容器为 P,则 Pi 记录二进制最高位 1 在第 i 位的数。显然,线性基大小应该是 log2Nmax 的(因为需要记录二进制的每一位)。
基本操作
插入
让我们给出一组数,从前往后扫。对于每一个数,我们找出它二进制最高位 1 所在的位置(暴力从最高位枚举即可),如果该位置对应的线性基为空,就插入这个数;如果不为空,则把这个数异或线性基上的数(x=x⊕Pi)继续找,直到找到能够插入的位置为止。
x 最终会被插入到线性基中,或者没有插入最终变成 0 。
举个栗子
给出这列数。
它们的二进制形式和二进制最高位 1 所在二进制位分别是
那让我们把它们插入线性基。
最终得到的线性基 P4…P0 分别为 23,9,5,2,0。
其二进制形式长这样 (是不是非常整齐呢)
代码
maxL
指的是最高的二进制位。如 long long
类型是 64 位整型,则最高位是第 62 位(0~63位,其中有一个是符号位),所以从第 62 位开始枚举即可。
合并线性基
暴力插入即可。(如果为空则插入,如果不为空就跳过)
线性基查询
查询最大异或和
我们从线性基的最高位开始枚举。显然越高位为 1 则异或和最大,所以可以采用一种贪心策略。
看到这里你就可以做出这道模板题了。
查询最小异或和
从线性基最低位枚举即可。线性基最低位上的数即为结果。
查询某个数是否可以异或得到
从高位到低位扫描。类似于插入操作只不过不进行插入。
如果第 i 位为 1,且该位对应的线性基不为空,则异或线性基上的数(x=x⊕Pi)继续扫描。
如果最后这个数变成了 0,则说明可以。
查询第 K 小异或和
再来一个数组来进行操作,将原来的线性基进行重新构造。
依然是从高位到低位枚举。若 j<i,当第 i 位线性基存在且该线性基上的数第 j 位为 1 时,就把 Pi 异或上 Pj(Pi=Pi⊕Pj)。
这样处理之后线性基每一位都相互独立了,大概长这样
最后从低位到高位扫描一下进行上述处理后的线性基,如果该位的线性基存在,则加入到新的数组中。
最后求第 K 大时只需要从高位到低位枚举,如果 K 的第 i 位为 1,则让 ans 异或新数组的第 i 位。(ans 初始值为 0)。
代码