求集合中选一个数与当前值进行位运算的max

求集合中选一个数与当前值进行位运算的max

这是一个听来的神仙东西。
先确定一下值域把,大概(2^{16}),再大点也可以,但是这里就只是写写,所以无所谓啦。

我们先看看如果暴力求怎么做,位运算需要给定(01/10,00,11)的关系,总共(8)种。
如果是暴力的话,我们的方法有两种,
第一种是比较喜闻乐见的,
我们对于当前数(x),暴力计算所有存在的数(a_i)中,(xoplus a_i)的最大值,这样的复杂度是(O(2^{16}))的。
另外一种也是不难考虑到的,
我们对于每个可能出现的数维护一个当前所有数的最大值。
也就是对于所有值域中的数,维护一个答案(ans)
然后依次插入所有集合中所有的数(a_i),每次暴力计算所有的答案的最大值,
也就是(ans[x]=max{xoplus a_i }),这样子询问的时候可以(O(1))查询。

两种方法一种是插入(O(1))询问(O(n)),另外一个是插入(O(n)),询问(O(1))
我们把两种东西结合一下,这样可以得到一个(O(sqrt n))的方法。
大致的方法如下:
我们对于每个数从中间分开,拆成前(8)个二进制位和后(8)个二进制位。
这样子我们可以预处理一个数组(pre[i][j])
表示集合中一个前(8)位是(i)的数,后(8)位能够和(j)进行位运算的最大值。
这样子(i,j)都是一个(8)位的数,总的空间和上述方法一样。
因为位运算是可以按位贪心的,所以对于查询一个数(x)
我们把它拆成(x=a imes 2^8+b)
每次先暴力(for)所有可能的前(8)位,找到与(a)能够构成最大值的那些数,
然后对于找到的所有数的前八位(p),直接查(pre[p][b])
因为前八位更大的数一定更大,那么影响结果的就只剩下后八位了,
把两个部分拼接起来就好了。
这样子暴力(for)前八位的复杂度是(O(2^8))
查找后面部分最大值的复杂度是(O(1))
所以这样子总的复杂度(O(2^8))
而对于集合中插入一个数,前(8)位唯一确定,每次只需要预处理后(8)位的结果。
时间复杂度还是(O(2^8))
总的复杂度还是(O(2^8))

原文地址:https://www.cnblogs.com/cjyyb/p/9388651.html