题目:
给 n 个数,从中选出 si , sj , sk 使得 (si+sj)⊕sk 最大,输出最大值。 n≤1000,si≤109
分析:
看见异或就换二进制。
枚举
si
和
sj
,对于每个和,都在字典树里逐位找使得异或结果最大的那个。找之前把
si,sj
从树里删掉。
注意字典树不一定非要对字符串操作,没必要把数字先变成字符串再操作。对于x, 逐位 x&(1 << i) 就可以得到每一位。同时,找的时候可以直接算出答案,而不用把最优串存下来再算结果。不要拘泥于模板。
代码:
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=1e3+5;
const double EPS=1e-8;
const int INF=0x3f3f3f3f;
const int MOD = 1e9+7;
struct Trie{
int n;
Trie *next[2];
};
Trie tree[MAXN*MAXN];
int n,a[MAXN];
char ans[MAXN];
int tot=-1;
void create(){
++tot;
tree[tot].n=0;
for(int i=0;i<2;i++)
tree[tot].next[i]=NULL;
}
void init(){
tot=-1;
create();
}
void insert(int x){
Trie *r=&tree[0];
for(int i=30;i>=0;i--){
int k = (x & (1 << i)) > 0;
if(r->next[k]){
r=r->next[k];
r->n++;
}
else{
create();
r->next[k]=&tree[tot];
r=&tree[tot];
r->n++;
}
}
}
void erase(int x){
Trie *r=&tree[0];
for(int i=30;i>=0;i--){
int k = (x & (1 << i)) > 0;
r=r->next[k];
r->n--;
}
}
int search(int x){
Trie* r=&tree[0];
int ret = 0;
for(int i=30;i>=0;i--){
int k = !((x & (1 << i)) > 0);
Trie* l1 = r->next[k],*l2 = r->next[1-k];
if(l1 && l1->n){
r = l1;
ret += (1 << i);
}
else{
r = l2;
}
}
return ret;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init();
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
insert(a[i]);
}
int Ans = 0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
erase(a[i]);
erase(a[j]);
Ans = max(Ans,search(a[i]+a[j]));
insert(a[i]);
insert(a[j]);
}
}
printf("%d\n",Ans);
}
return 0;
}