考场上想出来了。。。无奈被C卡了太久,打不完GG。。。。
首先,那个数组变与不变是没有多大区别的。。。因为异或满足结合律,所以我们可以把每一次操作都异或成一个操作,这样来看数组就是不变的。。
因为二进制中如果最高位取1,后面怎么取都不会比最高位取0来得小,所以我们可以考虑贪心一下
对于答案的每一位数尽量地去取0,这样得到的答案就是最优的
这样的操作可以用一个trie优化一把
把所有原序列中没有出现过的数插入到trie中,直接回答询问即可
代码:
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
typedef double DL;
const int INF = 2147483647;
const int maxn = 600100;
const int maxtrie = 12001000;
int n,m,x,rt,p[25],a[25];
int siz[maxtrie],ch[maxtrie][2],tot;
bool exist[maxn];
inline LL getint()
{
LL ret = 0,f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret * f;
}
inline int gcd(int a,int b)
{
return !b ? a : gcd(b,a % b);
}
inline void insert(int &o,int *T,int i)
{
if (!o) o = ++tot;
siz[o]++;
if (i == 20) return;
insert(ch[o][T[i + 1]],T,i + 1);
}
inline void find(int o,int *T,int i)
{
if (i == 20) return;
if (T[i + 1])
{
if (siz[ch[o][1]])
{
a[i + 1] = 0;
find(ch[o][1],T,i + 1);
}
else
{
a[i + 1] = 1;
find(ch[o][0],T,i + 1);
}
}
else
{
if (siz[ch[o][0]])
{
a[i + 1] = 0;
find(ch[o][0],T,i + 1);
}
else
{
a[i + 1] = 1;
find(ch[o][1],T,i + 1);
}
}
}
int main()
{
n = getint(); m = getint();
for (int i = 1; i <= n; i++) exist[getint()] = 1;
for (int i = 0; i <= 600000; i++)
{
if (exist[i]) continue;
int x = i;
for (int j = 20; j >= 1; j--)
{
a[j] = x & 1;
x >>= 1;
}
insert(rt,a,0);
}
x = 0;
for (int i = 1; i <= m; i++)
{
x = getint() ^ x;
int test;
int s = x;
for (int j = 20; j >= 1; j--)
{
p[j] = s & 1;
s >>= 1;
}
find(rt,p,0);
int ret = 0;
for (int j = 20; j >= 1; j--)
ret += a[j] ? 1 << (20 - j + 1 - 1) : 0;
printf("%d\n",ret);
}
return 0;
}