最大异或对C++


最大异或对

在给定的 N个整数 A1,A2……AN中选出两个进行 xor
(异或)运算,得到的结果最大是多少?

输入格式
第一行输入一个整数 N。

第二行输入 N个整数 A1~AN。

输出格式
输出一个整数表示答案。
在这里插入图片描述

本题采用字典树

首先,我们将所有读入的要进行比较的数存入字典树中。并利用son[N][2]数组记录每个节点的位置,这种记录方式是记录孩子的位置,我们可以很容易发现每个节点除了叶子节点外最多有两个分支,即为二进制表示的0或者1,由数据范围我们很容易得知我们记录的每一个数转为二进制存入trie后长度最多为31,所以开son数组的N=31100010,以son[1][1]=3为例,该数组元素表示1号节点的一个孩子值为1,并且这个孩子的节点为3。
存入一个数:我们从根节点开始遍历,最多31层。所以我们每个数据都是按二进制31位存,而先导0并不影响异或的结果。从第30位开始,利用u=x>>i&1得到第i位的u是0或是1,如果son[p][u]为0则说明能继续存,son[p][u]=++idx;,p再指向其孩子son[p][u]。
查询一个数的最大异或值:
同样从高位往低位查,越高位数据产生异或1说明该异或值越大,正印证了我们将高位存在距离根节点较近的层,我们去查这棵搭建好的trie树的子节点有没有可以异或为1的值,即son[p][!u]存不存在,如果存在就用res记录这个值,即该位为1,res=res
2+1,例如binary(10)2+1就为b(100+1)=b(101),b代表二进制,然后以p=son[p][!u]往下一层遍历。
如果son[p][!u]==0,那么该位异或为0,即res=res
2,p=son[p][u]。

代码如下(示例):

#include<iostream>
using namespace std;

const int N=31*100010;
const int m=100010;
int son[N][2];
int idx;
int a[m];



void insert(int x)
{
    int p=0;
    for(int i=30;i>=0;i--)
    {
        int u=(x>>i)&1;
        if(son[p][u]==0)
        {
            idx++;
            son[p][u]=idx;
        }
        p=son[p][u];
    }
}

int query(int x)
{
    int p=0;
    int res=0;
    for(int i=30;i>=0;i--)
    {
        int u=(x>>i)&1;
        if(son[p][!u])
        {
            p=son[p][!u];
            res=res*2+1;//异或后整体乘2来左移一位,例如高位10下一位异或后为1则binary(10)*2+1变为100+1为101
        }
        else
        {
            p=son[p][u];
            res=res*2;
        }
    }   
    return res;
}

int main()
{
    
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        insert(a[i]);
    }
    int max=0;
    for(int i=0;i<n;i++)
    {
        if(query(a[i])>=max)
        {
            max=query(a[i]);
        }
    }
    cout<<max;
    
    return 0;
}

总结

该题考查了字典树(trie)的用法,通过将每一个数据的二进制值存入字典树中,每次查询异或最大值只需遍历31层即可,避免了O(n^2)的复杂度,降为O(n)。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值