http://codeforces.com/contest/842/problem/D
1、整体的数组是不用变的,比如数组a[]经过一次询问x后,然后再询问y,相当于询问x ^ y ^ a[i]后的mex值
2、假设所求的答案是k,询问的数字是x,那么对于每个元素a[i],有a[i] ^ x != k恒成立。因为k是一个a[i]^x后得到的新数组,一个不存在新数组的数。所以若a[i] ^ x = k,则k不会是答案。
3、两个数相异或的结果是唯一的,即z ^ x 是一个确定值。
那么要求答案k,我肯定能找到一个数b,这个数不属于a[],使得别b ^ x = k
所以就相当于找一个数,异或x,得到的值最小,就是答案。
数b的范围是a[]的补集,因为a[]是3e5,所以补集大小开到1e6就够,不然这题用这个方法是做不了的。据说有一个好方法,但是还没想懂。
为什么最小是答案,因为数b[]异或x的结果肯定不会和a[]异或x的结果相同。证明:
若b[i] ^ x == a[i] ^ x,那么同时异或x,就等于b[i] = a[i]矛盾。
所以数b[]异或x的结果,每一个都是a[]异或x的结果中不存在的数。
那么找最小的那个就当然是答案
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; const int maxn = 1e6 + 20; int vis[maxn]; struct Node { struct Node *pNext[2]; } tree[maxn * 30]; int t; struct Node *create() { struct Node *p = &tree[t++]; for (int i = 0; i < 2; ++i) p->pNext[i] = NULL; return p; } void toInsert(struct Node **T, int val) { struct Node *p = *T; if (p == NULL) p = *T = create(); for (int i = 25; i >= 0; --i) { int id = ((1 << i) & val) > 0; if (p->pNext[id] == NULL) p->pNext[id] = create(); p = p->pNext[id]; } } int ask(struct Node *T, int val) { struct Node *p = T; LL ans = 0; for (int i = 25; i >= 0; --i) { int id = ((1 << i) & val) > 0; if (p->pNext[id]) p = p->pNext[id]; else { if (!p->pNext[!id]) return ans + (1 << i); ans += 1 << i; p = p->pNext[!id]; } } return ans; } void work() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) { int x; scanf("%d", &x); vis[x] = true; } struct Node *T = NULL; for (int i = 0; i <= maxn - 20; ++i) { if (!vis[i]) toInsert(&T, i); // printf("%d\n", i); } int haha = 0; for (int i = 1; i <= m; ++i) { int val; scanf("%d", &val); haha ^= val; printf("%d\n", ask(T, haha)); } } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif // printf("%d\n", 1 << 25); work(); return 0; }