题意:
给出 n(3≤n≤1000) 个数字,求 max(si+sj)⨁sk ,而且 i,j,k 互不相等。
分析:
把每个数字看成一个
01
字符串插入倒Trie树中去,枚举
i
和
j
,然后把
si
和
sj
从Trie树中删去。
然后在Trie树中贪心找到能与
si+sj
异或得到的最大值。
具体匹配的过程中是这样的,首先看树中最高位能否异或得到
1
。
能的话就往能的那个方向走,否则往另外一个方向走。
另外删除操作是这样实现的,我们每个节点记录一个
val
值。
插入时对所有经过节点的
val
值加
1
,删除就将对应节点的
val
值减
1
。
在树上匹配的时候就只走那些
val
值为正的节点。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
const int maxnode = 1e5+10;
int sz;//总共节点个数
int s[maxn], ch[maxnode][2], val[maxnode];
void init()
{
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
//d=1表示插入,d=-1表示删除
void update(int v, int d)
{
int u = 0;
for(int i = 30; i >= 0; i--)
{
int c = (v >> i) & 1;
if(!ch[u][c])
{
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
val[u] += d;
}
}
int match(int v)
{
int ans = 0, u = 0;
for(int i = 30; i >= 0; i--)
{
int c = (v >> i) & 1;
if(ch[u][c^1] && val[ch[u][c^1]])
{
ans |= (1 << i);
u = ch[u][c^1];
}
else
u = ch[u][c];
}
return ans;
}
int main()
{
int n, T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &s[i]);
update(s[i], 1);
}
int ans = (s[1] + s[2]) ^ s[3];
for(int i = 1; i <= n; i++)
{
update(s[i], -1);
for(int j = i + 1; j <= n; j++)
{
update(s[j], -1);
int t = match(s[i] + s[j]);
ans = max(ans, t);
update(s[j], 1);
}
update(s[i], 1);
}
printf("%d\n", ans);
}
return 0;
}
动态分配节点的写法:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
const int N = 2;
int s[maxn];
struct tree
{
int val;
tree *nxt[N];
tree()
{
for(int i = 0; i < N; i++)
nxt[i] = NULL;
val = 0;
}
}*root;
int a[33];
void ch(int x)
{
memset(a, 0, sizeof(a));
int len = 0;
while(x)
{
a[len++] = x % 2;
x /= 2;
}
}
void Insert(int x)
{
ch(x);
int len = 31;
tree *p = root;
while(len >= 0)
{
int id = a[len];
if(p -> nxt[id] == NULL)
{
tree *temp = new tree;
p -> nxt[id] = temp;
}
p = p -> nxt[id];
p -> val++;
len--;
}
}
int query(int x)
{
ch(x);
tree *p = root;
for(int i = 0; i < 31; i++)
a[i] ^= 1;
int len = 31;
int ans = 0;
while(len >= 0)
{
int id = a[len];
if(p -> nxt[id] == NULL || p -> nxt[id] -> val == 0)
id ^= 1;
if(id)
ans += 1 << len;
p = p -> nxt[id];
len--;
}
return ans ^ x;
}
void del(int x)
{
ch(x);
int len = 31;
tree *p = root;
while(len >= 0)
{
int id = a[len];
p -> nxt[id] -> val--;
p = p -> nxt[id];
len--;
}
}
void fre(tree *tmp)
{
for(int i = 0; i < N; i++)
if(tmp -> nxt[i])
fre(tmp -> nxt[i]);
delete(tmp);
}
int main()
{
int n, T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
root = new tree;
for(int i = 0; i < n; i++)
{
scanf("%d", &s[i]);
Insert(s[i]);
}
int ans = 0;
for(int i = 0; i < n; i++)
{
del(s[i]);
for(int j = i + 1; j < n; j++)
{
del(s[j]);
ans = max(ans, query(s[i] + s[j]));
Insert(s[j]);
}
Insert(s[i]);
}
printf("%d\n", ans);
fre(root);
}
return 0;
}