CH 1602 - The XOR Largest Pair - [字典树变形]

题目链接:传送门

描述
在给定的 $N$ 个整数 $A_1, A_2,\cdots,A_N$ 中选出两个进行xor运算,得到的结果最大是多少?

输入格式
第一行一个整数 $N$,第二行 $N$ 个整数 $A_1, A_2,\cdots,A_N$。

输出格式
一个整数表示答案。

样例输入
3
1 2 3

样例输出
3

数据范围与约定
对于100%的数据:$N \le 10^5, 0 \le A_i < 2^{31}$。

 

题解:

由于 $0 \le A_i < 2^{31}$,即二进制下最小是 $31$ 个 $0$,最大是 $31$ 个 $1$。将输入 $A_i$ 全部转化成长度为 $31$ 的 $0,1$ 字符串 $S_i$。

以最高位为字符串头,插入字典树。每次插入 $S_i$ 后,都在字典树中按贪心思路,尽可能找与 $S_i$ 相异的儿子节点(比如 $S_i$ 当前位为 $0$,那么我尽量找 $1$ 那个儿子,如果没有再找 $0$ 这个儿子)。

这样一来,每次插入 $S_i$ 后,都能找出 $A_1 \sim A_i$ 每个与 $A_i$ 异或的结果之中最大的。

那么,当 $A_1, A_2,\cdots,A_N$ 全部插入后,我就已经查找完所有满足 $i \le j$ 的 $A_i$XOR$A_j$,维护最大值即可。

 

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
namespace Trie
{
    const int SIZE=maxn*32;
    int sz;
    struct TrieNode
    {
        int ed;
        int nxt[2];
    }trie[SIZE];
    void init()
    {
        sz=1;
        memset(trie,0,sizeof(trie));
    }
    void insert(int x)
    {
        int p=1;
        for(int k=30;k>=0;k--)
        {
            int ch=(x>>k)&1;
            if(trie[p].nxt[ch]==0) trie[p].nxt[ch]=++sz;
            p=trie[p].nxt[ch];
        }
    }
    int MaxXor(int x)
    {
        int res=0;
        int p=1;
        for(int k=30;k>=0;k--)
        {
            int ch=(x>>k)&1;
            if(trie[p].nxt[ch^1])
            {
                p=trie[p].nxt[ch^1];
                res|=1<<k;
            }
            else p=trie[p].nxt[ch];
        }
        return res;
    }
};

int n;
int main()
{
    cin>>n;
    Trie::init();
    int ans=0;
    for(int i=1,x;i<=n;i++)
    {
        cin>>x;
        Trie::insert(x);
        ans=max(ans,Trie::MaxXor(x));
    }
    cout<<ans<<endl;
}

 

posted @ 2018-11-08 22:08  Dilthey  阅读(392)  评论(0编辑  收藏  举报