01字典树加强版HDU 5536
http://acm.hdu.edu.cn/showproblem.php?pid=5536
-
简化版题意:
在一个数组中找出 (s[i]+s[j])^s[k] 最大的值,其中 i、j、k 各不相同。 -
这个题目我们就不能直接套用模板了,问题出在哪里?是因为i、j、k不能相同,所以直接查询tire树会出现问题。怎么办?一个很直观的想法是删除。对k建trie树,枚举i、j,然后将i、j在trie树中删除。
-
考虑如何删除,我们用一个num数组记录每一个结点出现的次数(注意是每一个结点而不是结尾的结点,因为如果i,j两个位置的数字不能使用,那么在tire树上所有关于他的结点都不能使用),在每次insert的时候增加num,在每次删除的时候减少num,在最后查询的时候判断num是否为0代表当前树上这个结点是否可以使用。说到这里,这个题的大致思路就说完了,下面直接上代码。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define mk(a,b) make_pair(a,b)
#define ll long long
#define N 1010
using namespace std;
ll tot,ch[N*32][3],val[N*32],num[N*32],t,a[N];
void init()
{
tot=1;
ch[0][1]=0;ch[0][0]=0;
}
void insert(ll x)
{
ll u=0;
for(ll i=32;i>=0;i--)
{
ll v=(x>>i)&1;
if(!ch[u][v])
{
ch[tot][0]=0;ch[tot][1]=0;
val[tot]=0;
num[tot]=0;
ch[u][v]=tot++;
}
u=ch[u][v];
num[u]++;
}
val[u]=x;
}
void del(ll x,ll add)
{
ll u=0;
for(ll i=32;i>=0;i--)
{
ll v=(x>>i)&1;
u=ch[u][v];
num[u]+=add;
}
}
ll query(ll x)
{
ll u=0;
for(ll i=32;i>=0;i--)
{
ll v=(x>>i)&1;
if(ch[u][v^1]&&num[ch[u][v^1]]) u=ch[u][v^1];
else u=ch[u][v];
}
return x^val[u];
}
int main()
{
scanf("%lld",&t);
for(ll k=1;k<=t;k++)
{
ll n,ans=0;
init();
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
insert(a[i]);
}
for(ll i=1;i<=n;i++)
for(ll j=i+1;j<=n;j++)
{
del(a[i],-1);del(a[j],-1);
ans=max(ans,query(a[i]+a[j]));
insert(a[i]);insert(a[j]);
}
printf("%lld\n",ans);
}
return 0;
}