题目:http://acm.hdu.edu.cn/showproblem.php?pid=5536
题意:给你n个数,要找三个不同的数a[i],a[j],a[k]使(a[i]+a[j])^a[k]最大,求最大值
分析:对于异或的最大值问题,一般考虑用01字典树,先把这n个数插入字典树中,然后直接枚举a[i]+a[j],并从字典树中暂时删除a[i],a[j],在字典树中直接找与(a[i]+a[j])异或最大的数,并返回最大值,最后把这两个数从字典树中还原
Ac code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e3+5;///trie[i][j] 表示编号为i的节点的第j个儿子
ll trie[32*maxn][2];///注意数组要开32*maxn
ll val[32*maxn];
ll a[maxn];
int tot;
int num[32*maxn];
void init(){
memset(trie,0,sizeof trie);
memset(val,0,sizeof val);
memset(num,0,sizeof num);
tot=0;///用于对节点编号
}
void Insert(ll d)///插入节点
{
int rt=0;
for(int i=32; i>=0; --i)
{
int id=(d>>i)&1;
if(!trie[rt][id]) trie[rt][id]=++tot;///如果无该节点则新建
rt=trie[rt][id];///往下面走
num[rt]++;///记录每个节点出现的次数
}
val[rt]=d;///叶子节点的val数组为该数的值,其余非叶子为0
}
ll query(ll d)///询问与d异或的最大数并返回最大值
{
int rt=0;
for(int i=32; i>=0; --i)
{
int id=(d>>i)&1;
if(trie[rt][id^1]&&num[trie[rt][id^1]]) rt=trie[rt][id^1];
else rt=trie[rt][id];
}
return d^val[rt];
}
void update(ll a,int b)///用来间接删除节点,与num数组配合
{
int rt=0;
for(int i=32;i>=0;--i){
int id=(a>>i)&1;
rt=trie[rt][id];
num[rt]+=b;
}
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
Insert(a[i]);
}
ll _max=0;
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
{
update(a[i],-1),update(a[j],-1);///先删除这两个数在字典树中的所有节点
_max=max(_max,query(a[i]+a[j]));
update(a[i],1),update(a[j],1);///后还原
}
printf("%lld\n",_max);
}
return 0;
}
题目:http://codeforces.com/contest/706/problem/D
题意:给你三种操作
1、+ x 表示向集合里添加x
2、 - x 表示去除集合里的x,但保证在次之前集合里有x
3、?x 表示x与集合里的数异或的最大值是多少?
分析:同上。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+1;
ll trie[32*maxn][2];
ll val[32*maxn];
int num[32*maxn];
int tot;
void init()
{
memset(trie,0,sizeof trie);
memset(val,0,sizeof val);
memset(num,0,sizeof num);
tot=0;
}
void Insert(ll d)
{
int rt=0;
for(int i=32; i>=0; --i)
{
int id=(d>>i)&1;
if(!trie[rt][id]) trie[rt][id]=++tot;
rt=trie[rt][id];
num[rt]++;
}
val[rt]=d;
}
ll query(ll d)
{
int rt=0;
for(int i=32; i>=0; --i)
{
int id=(d>>i)&1;
if(trie[rt][id^1]&&num[trie[rt][id^1]]) rt=trie[rt][id^1];
else rt=trie[rt][id];
}
return d^val[rt];
}
void update(ll a,int b)
{
int rt=0;
for(int i=32; i>=0; --i)
{
int id=(a>>i)&1;
rt=trie[rt][id];
num[rt]+=b;
}
}
int main()
{
int q;
char ch;
init();
scanf("%d",&q);
getchar();
while(q--)
{
ll x;
scanf("%c%lld%*c",&ch,&x);
if(ch=='+')
Insert(x);
else if(ch=='-')
update(x,-1);
else if(ch=='?')
printf("%lld\n",max(query(x),x));
}
return 0;
}