D. Vitya and Strange Lesson

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;
}

 

posted on 2017-09-02 19:55  stupid_one  阅读(281)  评论(0编辑  收藏  举报

导航