HDU4825 Xor Sum

题意

给定一个集合后, 求一组查询中每个数和集合中任一元素异或的最大值.

题解

异或的规律是这样的 1 ^ 1 = 0, 0 ^ 0 = 0, 1 ^ 0 = 1, 0 ^ 1 = 1, 而最大值即是代表了, 在 靠前的位置 上有 **尽量多的 1 **. 因此, 对于答案来说, 等价于靠前的位置 上有 尽量与查询数值对应位不相同的数字

这类题目可以用 01TrieO(1) 的时间内完成对 一个查询 的求解.

具体思路: 对于一个数字, 首先取反(也可以不取反, 只不过后续判断条件会有稍微变化), 从 高位到低位 依次遍历 指向 0 所代表的子树 的指针指向 1 所代表的子树 的指针 是否为 NULL, 如果不为空则继续下一层, 否则就向当前节点的另一个分支遍历.

AC代码

#include <cstdio>
#include <iostream>
using namespace std;
const int ARRSIZE = 2;
struct TrieNode {
    TrieNode* next[ARRSIZE];
    TrieNode() {
        for(int i = 0; i < ARRSIZE; i++)
            next[i] = NULL;
    }
};
void insertNum(TrieNode* root, unsigned num) {
    TrieNode* p = root;
    for(int i = 31; i >= 0; i--) {
        int bit = (num >> i) & 1;
//        cout << " bit is " << bit;
        if(!p->next[bit])
            p->next[bit] = new TrieNode();
        p = p->next[bit];
    }
//    cout << endl;
}
int searchNum(TrieNode* root, int num) {
    num = ~num;
    int ret = 0;
    TrieNode* p = root;
    for(int i = 31; i >= 0; i--) {
        int index = (num >> i) & 1;

        if(!p->next[index])
            index = 1 - index;
        ret += (index << i);
        p = p->next[index];
    }
    return ret;
}
int main() {
    int nTest; scanf("%d", &nTest);
    for(int t = 1; t <= nTest; t++) {
        printf("Case #%d:\n", t);
        TrieNode* root = new TrieNode();
        int nNum, nQuery;
        scanf("%d %d", &nNum, &nQuery);
        while(nNum--) {
            unsigned num; scanf("%u", &num);
            insertNum(root, num);
        }
        while(nQuery--) {
            int tar; scanf("%u", &tar);
            printf("%u\n", searchNum(root, tar));
        }
    }
    return 0;
}

posted @ 2018-04-04 23:53  1pha  阅读(104)  评论(0编辑  收藏  举报