• 求集合中选一个数与当前值进行位运算的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))

  • 相关阅读:
    Ansible自动部署lnmp架构+上线电商
    elastalert 基于EFK环境的邮件报警
    冒泡法、选择法、插入法排序
    Java的基本数据类型
    cmd运行java程序找不到或无法加载主类解决办法
    JavaBean进行表单开发
    Web项目各目录详解
    【数论】整数分块及详细证明
    题解 P4874 【[USACO14DEC] Piggyback_Silver 背负式运输(银)】
    题解 P3792 【由乃与大母神原型和偶像崇拜】
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9388651.html
Copyright © 2020-2023  润新知