您的位置:首页 > 其它

HDU 5536 Chip Factory(01字典树)

2017-07-24 17:05 531 查看
【题目链接】HDU 5536

【题意】给定一组数字,求这组数字中两数之和与第三个数抑或的最大值。

【样例】



【分析】求某个数和一组数的最大抑或值可以用01字典树。这里就是在此基础上增加了一些操作。先将所有数字插入字典树,枚举两数之和,删去这两个数在字典树中的记录,然后插入两数之和与字典树中记录数字的最大抑或值,单次查询后,在将这两个删去的数插入字典树。取所有查询结果的最大值,即为所求。这道题相比博客里的上一道01字典树,多的主要就是删去字典树中单条记录的操作。具体细节看注释。

【代码】

#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1005;
const int N=2;
struct Trie{
int num;
Trie*nxt
;
};
Trie*root;
int s[33],x[33],y[33];
long long M;
void init(Trie*t){
for(int i=0;i<N;i++)
t->nxt[i]=NULL;
t->num=0;
}
void build(){
root=new Trie;
init(root);
}
void insert(int str[]){
Trie*p=root;
for(int i=0;i<32;i++){
int id=str[i];
if(p->nxt[id]==NULL){
Trie*t=new Trie;
init(t);
p->nxt[id]=t;
}
p=p->nxt[id];
p->num++;
}
}
int find(int str[]){
Trie*p=root;
for(int i=0;i<32;i++){
int id=str[i];
id=!id;
if(p->nxt[id]==NULL||p->nxt[id]->num==0){
//这里的p->nxt[id]->num==0是配合del函数的一个判断
id=!id;
}
M+=id*(1<<(31-i));
p=p->nxt[id];
}
return 0;
}
void del(int str[]){
Trie*p=root;
for(int i=0;i<32;i++){
p=p->nxt[str[i]];

4000
p->num--;
//删去记录的方式是num--,配合find函数来看
}
}
int main(){
int T,N;
int ipt[maxn];
long long ans;
cin>>T;
for(int k=0;k<T;k++){
cin>>N;
build();
for(int i=0;i<N;i++){
scanf("%d",&ipt[i]);
for(int j=0;j<32;j++) {
s[j]=(ipt[i]>>(31-j))&1;
}
insert(s);
}
ans=0;
for(int i=0;i<N;i++){
for(int k=0;k<32;k++) {
x[k]=(ipt[i]>>(31-k))&1;
}
del(x);
//删去ipt[i]
for(int j=i+1;j<N;j++){
M=0;
for(int k=0;k<32;k++) {
y[k]=(ipt[j]>>(31-k))&1;
}
del(y);
//删去ipt[j]
long long sum=ipt[i]+ipt[j];
for(int k=0;k<32;k++) {
s[k]=(sum>>(31-k))&1;
}
find(s);
//查询ipt[i]+ipt[j]与字典树中能产生最大抑或的数字,存在M中
insert(y);
//再次插入ipt[j]
long long XOR=sum^M;
ans=max(XOR,ans);
}
insert(x);
//再次插入ipt[i]
}
cout<<ans<<endl;
}
return 0;
}


【说明】15年的长春现场赛题,据说现场赛的时候可以用n^3暴力过…十分考验勇气,太可怕了。不过试了试hdu,现在暴力貌似已经不能过了。写这道题的时候主要是没想到还有删去单条记录这种姿势,思考着如何标记就陷入了困境。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: