题意:
给出 n ( 3 ≤ n ≤ 1000 ) n(3\le n\le1000) n(3≤n≤1000)个非负整数 s 1 , s 2 , ⋯   , s n s_1,s_2,\cdots,s_n s1,s2,⋯,sn,求最大的 ( s i + s j ) ⊕ s k (s_i+s_j)\oplus s_k (si+sj)⊕sk,其中 i , j , k i,j,k i,j,k互不相同且 1 ≤ i , j , k ≤ n 1\le i,j,k\le n 1≤i,j,k≤n。
分析:
由于 n n n只有 1000 1000 1000,所以我们可以暴力枚举 i , j i,j i,j,然后在除 s i , s j s_i,s_j si,sj以外元素构成的01字典树中找到异或最大的 s k s_k sk。
每次都去建树肯定不行,所以就要加一个数组 n u m [ u ] num[u] num[u]来实现带删除操作的01字典树,先把 s 1 s_1 s1~ s n s_n sn都放入01字典树,枚举了 i , j i,j i,j就删除 s i , s j s_i,s_j si,sj,询问最大异或值后再将 s i , s j s_i,s_j si,sj恢复即可。
以下代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1000+50;
const int max_base=31;
int n;
int ch[31*maxn][2],num[31*maxn],tot;
LL s[maxn],val[31*maxn];
void init()
{
tot=1;
ch[0][0]=ch[0][1]=0;
val[0]=0;
num[0]=0;
}
void ins(LL x)
{
int u=0;
num[u]++;
for(LL i=max_base;i>=0;i--)
{
LL c=(x>>i)&1LL;
if(!ch[u][c])
{
ch[tot][0]=ch[tot][1]=0;
val[tot]=0;
num[tot]=0;
ch[u][c]=tot++;
}
u=ch[u][c];
num[u]++;
}
val[u]=x;
}
void updata(LL x,int op) //op=-1:删除x
{ //op=1:恢复之前被删除的x
int u=0;
num[u]+=op;
for(LL i=max_base;i>=0;i--)
{
LL c=(x>>i)&1LL;
u=ch[u][c];
num[u]+=op;
}
}
LL query(LL x)
{
int u=0;
for(LL i=max_base;i>=0;i--)
{
LL c=(x>>i)&1LL;
if(ch[u][c^1]&&num[ch[u][c^1]])
u=ch[u][c^1];
else
u=ch[u][c];
}
return x^val[u];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&s[i]);
ins(s[i]);
}
LL ans=0;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
LL x=s[i]+s[j];
updata(s[i],-1);
updata(s[j],-1);
ans=max(ans,query(x));
updata(s[i],1);
updata(s[j],1);
}
}
printf("%lld\n",ans);
}
return 0;
}