UVALive4682 XOR Sum

UVALive4682 XOR Sum

题意

给定一个数组, 求连续子序列中异或值最大的值.

题解

假设答案区间为 [L, R], 则答案为 XOR[L, R], 可以将区间分解为 XOR[L,R] == XOR[0, L - 1] ^ XOR[L, R],

因此

  1. 不断更新所以数字的 前缀异或和, 将每一个前缀异或和 都 保存到 01Trie
  2. 01Trie 中查询与它 异或值最大 的 前缀异或和
  3. 根据 Step2 的结果, 更新 ans. 重复第一步, 直至无剩余元素.

需要注意的是, 对于样例中的 3 8 2 6 4 的 前缀异或和分别 为 3 11 9 15 11, 最大值为15, 区间为 [0, 4), 因此每个Trie的初始状态应存在 0.

AC代码

#include <cstdio>
using namespace std;
int max(int a, int b) {
    return a > b ? a : b;
}
struct BinTrie {
    BinTrie* next[2];
    BinTrie() {
        next[0] = next[1] = NULL;
    }
};
void insertNum(BinTrie* root, unsigned num) {
    BinTrie* p = root;
    for(int i = 31; i >= 0; i--) {
        int index = (num >> i) & 1;
        if(!p->next[index])
            p->next[index] = new BinTrie();
        p = p->next[index];
    }
}
unsigned queryDiff(BinTrie* root, unsigned num) {
    num = ~num;
    BinTrie* p = root;
    unsigned ret = 0;
    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);
    while(nTest--) {
        int nNum; scanf("%d", &nNum);
        unsigned pre = 0, ans = 0;
        BinTrie* root = new BinTrie();
      	// 保证了 [0, x) 区间的合理性
      	// 否则对于 15 来说, Trie中最大不同的前缀异或和 queryDiff(root, pre) 并不为 0
        insertNum(root, 0);
        while(nNum--) {
            unsigned num; scanf("%u", &num);
            pre = pre ^ num;
            insertNum(root, pre);
            ans = max(ans, queryDiff(root, pre) ^ pre);
        }
        printf("%u\n", ans);
    }
    return 0;
}

posted @ 2018-04-05 10:26  1pha  阅读(120)  评论(0编辑  收藏  举报