给出n个数,第i个数为(a_i),问从中任意取两个数,进行异或运算,得到的结果的最大值,(nleq 10^5)。
解
首先暴力的思路是枚举每一个数,再确定另外一个数,现在问题是如何快速确定另外一个数。
二进制运算问题,采用二进制拆分,对每一位,尤其是从最高位考虑,尽可能选择一堆数,让最高位不为0,在从选出的一堆数再选一堆数,让次高位尽可能不为0,不停地缩小集合范围,就能得到我们的答案.
于是问题变成如何快速检索每一位对应的集合,这样我们就可以利用trie树来做了,因为它可以查询某一位一个字符对应的字符串,于是我们把数字看成01串,加入trie树,按照上面所说的思路即可,时间复杂度(O(nlog(n)))。
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define Size 3100000
using namespace std;
int trie[Size][2],tot,
a[100005];
il int ask(int);
il void insert(int),
read(int&);
template<class free>
il free Max(free,free);
int main(){
int n,ans(0);read(n);
for(int i(1);i<=n;++i)
read(a[i]),insert(a[i]);
for(int i(1);i<=n;++i)
ans=Max(ans,ask(a[i]));
printf("%d",ans);
return 0;
}
template<class free>
il free Max(free a,free b){
return a>b?a:b;
}
il void read(int &x){
x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
il int ask(int x){int p(0),ans(0);
for(int i(30);i>=0;--i)
if(trie[p][x>>i&1^1])
p=trie[p][x>>i&1^1],ans|=1<<i;
else p=trie[p][x>>i&1];
return ans;
}
il void insert(int x){int p(0);
for(int i(30);i>=0;--i){
if(!trie[p][x>>i&1])
trie[p][x>>i&1]=++tot;
p=trie[p][x>>i&1];
}
}