最大异或对(Trie)

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

输入格式

第一行输入一个整数N。

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

输出格式

输出一个整数表示答案。

数据范围

1≤N≤105,
0≤Ai<2^31

输入样例:

3
1 2 3

输出样例:

3

思路:

用Trie(字典树),建树时,根据每个数字的对应的二进制串构造一个二叉树,每个结点两个分支,分支指向的两个son结点分别表示当前位的数值为0或1,记录每次输入的数字转化成的二进制串,当前位为1,就走到数值为1的结点,否则走到0结点,这样每个数字对应的Trie中的路径就是唯一的。

因为要求异或值最大,所以用贪心的思想,在第一个数字固定的情况下,尽可能地让第二个数的每一位都与第一个数的对应位相反,这样最终确定的第二个数与第一个数的异或值就最大,所以在查询时,遍历第一个串o(n),根据固定的第一个二进制串,每次尽可能走到与当前位的值相反的结点,这样的路径对应的就是与第一个二进制串异或值最大的二进制串,便利了这个数的位数次o(logn),所以总的时间复杂度o(n*logn);

完整代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int maxn=3e6+5;

int n,a[maxn];
int son[maxn][2],idx;

void insert(int x)
{
    int p=0;
    for(int i=30;~i;i--){//最大0-30共31位,从最高位30位开始往前枚举每一位
        int &s=son[p][x>>i&1];//x从右往左第i位是几就走到值为几的结点
        if(!s) s=++idx;
        p=s;
    }
}

int query(int x)
{
    int p=0,res=0;
    for(int i=30;~i;i--){
        int k=x>>i&1;
        if(!son[p][!k]) p=son[p][k];//若数值与当数字前位的数值相反的结点不存在,则只能走到与当前位数值相同的结点
        else{
            p=son[p][!k];//否则尽可能走到与当前位数值相反的结点,这样按位异或结果最大
            res+=1<<i;//当前为数值与当数字前位的数值相反的结点,所以当前位异或结果为1,算上位的权值,对最终结果的贡献值就是1<<i
        }
    }
    return res;
}

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值