题意:给定一个集合和多个询问,每个询问为一个数,输出集合中的一个数使得该数与询问的异或和最大。
思路:
经典题。
对于集合中的每一个数从高位到低位插入一棵01字典树,然后对于每一个询问的数 x <script type="math/tex" id="MathJax-Element-35">x</script>,将x二进制分解后从高位进行匹配,尽量匹配相反的数(0匹配1,1匹配0),使异或后高位尽量出现1。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int A = 1e5 + 10;
int Trie[A*16][2],val[A*16],tot,n,m,x;
void init(){
tot = 0;
memset(val,0,sizeof(val));
memset(Trie,0,sizeof(Trie));
}
void insert(ll v){
int u = 0;
for(int i=32 ;i>=0 ;i--){
int c = (v>>i)&1;
if(!Trie[u][c]) Trie[u][c] = ++tot;
u = Trie[u][c];
}
val[u] = v;
}
int query(ll v){
int u = 0;
for(int i=32 ;i>=0 ;i--){
int c = (v>>i)&1;
if(Trie[u][c^1]) u = Trie[u][c^1];
else u = Trie[u][c];
}
return val[u];
}
int main(){
int T,_=1;T = read();
while(T--){
init();printf("Case #%d:\n",_++);
n = read();m = read();
for(int i=1 ;i<=n ;i++){x = read();insert(x);}
for(int i=1 ;i<=m ;i++){
x = read();
printf("%d\n",query(x));
}
}
return 0;
}