zoukankan      html  css  js  c++  java
  • SPOJ SUBXOR

    SPOJ SUBXOR

    题意

    给定一个由正整数构成的数组, 求 异或和小于k 的子序列的个数.

    题解

    假设答案区间为 [L, R], XOR[L, R] 等价于 XOR[1, L - 1] ^ XOR[1, R], 可以使用 01Trie 保存目前已有的 前缀异或和, 对于每一个新的前缀插入之前, 在 01Trie 中查询 与 新的前缀 异或值 小于 K 的 已有前缀和的个数.

    对于每个TrieNode 的定义为

    struct TrieNode {
        TrieNode* next[2];
        int cnt;
        TrieNode() {
            next[0] = next[1] = NULL;
          	// 保存当前前缀的个数
            cnt = 0;
        }
    };
    

    在进行查询时, 比较 新的前缀和 and k 的每一位

    已有前缀和的第 i 位 indexPre( 新的前缀和的第 i 位) indexK( K 的第 i 位) 相应操作
    0 0 0 递归求解左子树
    1 0 1 统计左子树叶子节点个数, 递归求解右子树
    1 1 0 递归求解右子树
    0 1 1 统计右子树叶子节点个数, 递归求解左子树

    对于 indexPre == 0, indexK == 0 的情况来说, 已有前缀和为 0 时满足条件, 因此需要递归求解左子树. 当已有前缀和为 1 时, indexK == 1, 大于要求的值, 所以不继续递归.

    对于 indexPre == 0, indexK == 1 的情况来说, 已有前缀和为 1 时满足条件, 但 右子树 中可能有 值大于等于 K 的叶子节点, 因此需要递归求解右子树. 当已有前缀和为 0 时, indexK == 0, 所有左子树的叶子节点的值均小于 K, 因此统计左子树叶子节点的个数

    AC代码

    #include <cstdio>
    #include <iostream>
    using namespace std;
    struct TrieNode {
        TrieNode* next[2];
        int cnt;
        TrieNode() {
            next[0] = next[1] = NULL;
            cnt = 0;
        }
    };
    void insertNum(TrieNode* root, unsigned num) {
        TrieNode* p = root;
        for(int i = 31; i >= 0; i--) {
            int index = (num >> i) & 1;
            if(!p->next[index])
                p->next[index] = new TrieNode();
            p = p->next[index];
            p->cnt++;
        }
    }
    int getCnt(TrieNode* root) {
        return root ? root->cnt : 0;
    }
    int queryLessThanK(TrieNode* root, int pre, int k) {
        TrieNode* p = root;
        int ret = 0;
        for(int i = 31; i >= 0; i--) {
            if(p == NULL)
                break;
            int indexPre = (pre >> i) & 1; // prefiexbit
            int indexK = (k >> i) & 1; // bit
            if(indexPre == indexK) {
                if(indexK)
                    ret += getCnt(p->next[1]);
                p = p->next[0];
            }
            else if(indexPre != indexK) {
                if(indexK)
                    ret += getCnt(p->next[0]);
                p = p->next[1];
            }
        }
        return ret;
    }
    int main() {
        int nTest; scanf("%d", &nTest);
        while(nTest--) {
            int nNum, k;
            scanf("%d %u", &nNum, &k);
            TrieNode* root = new TrieNode();
            // insertNum(root, 0) 保证了前缀异或和 pre 自身 可以小于 k
            insertNum(root, 0);
            unsigned pre = 0;
            long long ans = 0;
            while(nNum--) {
                unsigned num; scanf("%u", &num);
                pre = pre ^ num;
                ans += queryLessThanK(root, pre, k);
                insertNum(root, pre);
            }
            cout << ans << endl;
        }
        return 0;
    }
    
    
  • 相关阅读:
    【bzoj2821】作诗(Poetize)
    ZOJ-2112-Dynamic Rankings(线段树套splay树)
    POJ- 2104 hdu 2665 (区间第k小 可持久化线段树)
    hust-1024-dance party(最大流--枚举,可行流判断)
    hdu-3046-Pleasant sheep and big big wolf(最大流最小割)
    POJ-3294-Life Forms(后缀数组-不小于 k 个字符串中的最长子串)
    POJ-Common Substrings(后缀数组-长度不小于 k 的公共子串的个数)
    POJ-2774-Long Long Message(后缀数组-最长公共子串)
    POJ-3693-Maximum repetition substring(后缀数组-重复次数最多的连续重复子串)
    spoj-694-Distinct Substrings(后缀数组)
  • 原文地址:https://www.cnblogs.com/1pha/p/8726928.html
Copyright © 2011-2022 走看看