调了好久,对着好多代码对了老半天,最终结果是数组开小了。以前学Trie的时候学的是用结构体和指针的,对这种数组模拟的还真拿捏不好。
参考:http://blog.youkuaiyun.com/mengxiang000000/article/details/77718605
涨知识了,有学到了Trie的新用法。
题意就是给你n个数,询问m次,每次询问给你一个x,让你求这n个数异或x之后,查询这n个数字的mex,mex就是自然数中第一个没有出现过的数。当初看到这题,脑袋闪过的就是暴力过不去,除了暴力,别的还想不到。
思路:假设现在有0-(k-1)这k个不同的数字,从中抽出来n个数字作为输入的数字。这n个数字分别对x进行异或运算,得到了一个新的序列,这个序列的mex就是那(k-n)个数字中异或x的最小值。因为这k个数字,从中抽出来n个异或x,异或后的新序列中没出现过的数字肯定是那(k-n)个数字对x异或的值。
#include <bits/stdc++.h>
using namespace std;
const int N = 19;
bool mark[1<<N];
struct Trie
{
int next[(1<<N)*20][2];
int sz;
void init()
{
memset(next,-1,sizeof(next));
sz = 0;
}
void insert(int num)
{
int cur = 0;
for(int i = N-1; i >= 0; --i)
{
int t = (num>>i)&1;
if(next[cur][t] == -1)
next[cur][t] = ++sz;
cur = next[cur][t];
}
}
int query(int num)
{
int ret = 0;
int cur = 0;
for(int i = N-1; i >= 0; --i)
{
int t = (num>>i)&1;
if(next[cur][t] != -1)
{
cur = next[cur][t];
ret |= t<<i;
}
else
{
t = !t;
cur = next[cur][t];
ret |= t<<i;
}
}
return ret;
}
};
Trie t;
int main()
{
t.init();
int n,m,num;
scanf("%d %d",&n,&m);
for(int i = 0; i < n; ++i)
{
scanf("%d",&num);
mark[num] = true;
}
for(int i = 0; i < (1<<N); ++i)
{
if(!mark[i])
t.insert(i);
}
int q = 0;
while(m--)
{
scanf("%d",&num);
q ^= num;
printf("%d\n",t.query(q)^q);
}
return 0;
}