题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5536
题意:求max( (a[i] + a[j]) ^ a[k] ) (i, j, k都不相同) ^异或
思路:一开始的想法就是n^3的暴力枚举,发现复杂度太大之后开始逐步优化。
第一次的想法就是n^2的枚举a[i]和a[j],然后对已经从小到大排序完之后的a【】数组进行二分查找来从左往右确定与(a[i] + a[j])异或最大值的数,因为尽可能的大,所以0找1,1找0.但最后还是会超时。
最后想到用数据结构字典树来存所有的数,这样每次的查找不用一位一位的进行二分查找确认,只要走一遍字典树的根节点到子节点就好了。具体方法如下:
建一个字典树直接找,每次先删除a[i],a[j]然后找出剩下的与a[i]+a[j]的最大异或和,然后然把a[i],a[j]插回去
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100010;
int T_T,n,a[MAXN];
struct Trie
{
int ch[2],size;
}T[MAXN];
int root=1,tot=1;
void Insert(int x)
{
int o=root;
T[o].size++;
for(int k=30;k>=0;k--)
{
int c;
if(x&(1<<k))
c=1;
else
c=0;
if(!T[o].ch[c])
T[o].ch[c]=++tot;
o=T[o].ch[c];
T[o].size++;
}
}
void Delete(int x)
{
int o=root;
T[o].size--;
for(int k=30;k>=0;k--)
{
int c;
if(x&(1<<k)) c=1;
else c=0;
o=T[o].ch[c];
T[o].size--;
}
}
int Query(int x)
{
int o=root;
for(int k=30;k>=0;k--)
{
int c;
if(x&(1<<k)) c=1;
else c=0;
if(c==1)
{
if(T[o].ch[0]&&T[T[o].ch[0]].size)
o=T[o].ch[0];
else
o=T[o].ch[1],x^=(1<<k);
}
else
{
if(T[o].ch[1]&&T[T[o].ch[1]].size)
o=T[o].ch[1],x^=(1<<k);
else
o=T[o].ch[0];
}
}
return x;
}
int main()
{
scanf("%d",&T_T);
while(T_T--)
{
int ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
Insert(a[i]);
for(int i=1;i<=n;i++)
{
Delete(a[i]);
for(int j=i+1;j<=n;j++)
{
Delete(a[j]);
ans=max(ans,Query(a[i]+a[j]));
Insert(a[j]);
}
Insert(a[i]);
}
printf("%d\n",ans);
for(int i=1;i<=tot;i++)
T[i].ch[0]=0,T[i].ch[1]=0,T[i].size=0;
tot=1;
}
return 0;
}