题意:有一个数组a[], 包含n个数,从n个数中找到三个数使得 (a[i]+a[j])⊕a[k]最大,i,j,k不同;
求异或的结果最大所以我们可以用01字典树,先把所有的数加入字典树中,从n个数中选出两个数a[i]和a[j],
先把他们从字典树中删除,然后找到与a[i]+a[j]异或最大的数,和结果取最大值即可;
最后不要忘记再把a[i]和a[j]添加到字典树中即可;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
using namespace std;
#define met(a, b) memset(a, b, sizeof(a))
#define N 1005
#define INF 0x3f3f3f3f
typedef long long LL;
struct node
{
int num, sum;///num是当前的数,sum表示是否存在;
node* Next[2];
};
void Add(node* head, int x, int cnt)
{
node *p = head;///移动指针;
for(int i=31; i>=0; i--)
{
int k = (x>>i)&1;///表示x对应的二进数从右边数第i位是k(0或1);
if(p->Next[k] == NULL)///如果不存在就新建一个节点;
{
node* q = new node();
p->Next[k] = q;
}
p = p->Next[k];///移动指针指向下一节点;
p->sum += cnt;///当前节点可达;更新一下,如果是添加x则+1,删除x则-1;
}
p->num = x;///在结束的时候记录从head到当前位置所表示的数是x;
}
int Find(node* head, int x)
{
node *p = head;
for(int i=31; i>=0; i--)
{
int k = (x>>i)&1;
if(p->Next[k^1] != NULL && p->Next[k^1]->sum > 0)///每次尽量往不同的方向走,前提是存在不同的节点;
p = p->Next[k^1];
else
p = p->Next[k];
}
return (p->num^x);///最后找到的p->num就是与x异或最大的数;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, a[N];
node *head = new node();
scanf("%d", &n);
for(int i=1; i<=n; i++)
{
scanf("%d", &a[i]);
Add(head, a[i], 1);///添加所有的数到字典树中去;
}
int ans = 0;
///从n个数中选出两个数a[i]和a[j],先把他们从字典树中删除,
///然后找到与a[i]+a[j]异或最大的数,和结果取最大值即可;
///最后不要忘记再把a[i]和a[j]添加到字典树中即可;
for(int i=1; i<=n; i++)
{
Add(head, a[i], -1);
for(int j=1; j<=n; j++)
{
if(i==j)continue;
Add(head, a[j], -1);
int ret = Find(head, a[i]+a[j]);
ans = max(ans, ret);
Add(head, a[j], 1);
}
Add(head, a[i], 1);
}
printf("%d\n", ans);
}
return 0;
}