链接
题意
给出n个数(n >= 3),求n个数中任意三个不同的数a、b、c的(a + b) ^ c的最大值。
题解
一种trie树的经典用法,和异或操作结合求最值的问题。
将输入的数二进制化后,全部存在trie树中(注意补齐到31位),然后枚举a和b,在trie树中寻找相应的c即可。
由于要满足a、b、c不同,在选定a、b后需要将他们的二进制串从trie树中消除,得出结果后再添加进去,这里用一个路径去计数就可以了,详情看代码。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn (1010)
int trie_nd[1010];
struct Trie
{
#define maxk (40000)
#define degree (2)
#define next nnext
#define prev pprev
int next[maxk][degree], prev[maxk], nd[maxk], inc_nod[maxk];
int L, root;
int newnode()
{
next[L][0] = next[L][1] = -1;
nd[L] = inc_nod[L] = prev[L] = 0;
return L++;
}
int init() { L = 0; root = newnode(); }
void insert(int val[], int n, int id)
{
int now = root;
for(int i = 0, key; i < n; i++)
{
key = val[i];
if(next[now][key] == -1)
next[now][key] = newnode();
prev[next[now][key]] = now;
now = next[now][key];
inc_nod[now]++;
}
nd[now] = 1;
trie_nd[id] = now;
}
void recall(int nodid, int val)
{
if(nodid == root) return;
inc_nod[nodid] += val;
recall(prev[nodid], val);
}
int solve(int val[], int n)
{
int now = root, ret = 0;
for(int i = 0, need; i < n; i++)
{
need = val[i] ? 0 : 1;
if(next[now][need] == -1 || !inc_nod[next[now][need]])
{
ret <<= 1;
ret |= 0;
now = next[now][need^1];
}
else
{
ret <<= 1;
ret |= 1;
now = next[now][need];
}
}
return ret;
}
} trie;
int buf[50], buf0[50];
int* to01(int x)
{
int k = 0;
while(x) { buf0[k++] = x & 1; x >>= 1; }
int i;
for(i = 0; i < 31 - k; i++) buf[i] = 0;
while(k) { buf[i++] = buf0[k-1]; k--; }
return buf;
}
int str01[maxn][32], a[maxn];
int main()
{
int T;
cin >> T;
while(T--)
{
trie.init();
int n;
cin >> n;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
trie.insert(to01(a[i]), 31, i);
}
int ans = 0;
for(int i = 1; i < n; i++)
{
for(int j = i + 1; j <= n; j++)
{
trie.recall(trie_nd[i], -1);
trie.recall(trie_nd[j], -1);
ans = max(ans, trie.solve(to01(a[i] + a[j]), 31));
trie.recall(trie_nd[i], 1);
trie.recall(trie_nd[j], 1);
}
}
cout << ans << endl;
}
return 0;
}