zoukankan      html  css  js  c++  java
  • E. Beautiful Subarrays 字典树

    http://codeforces.com/contest/665/problem/E

    给定一个序列,问其中有多少个区间,所有数字异或起来 >= k

    看到异或,就应该想到异或的性质,A^B^B = A,所以,用sum[i]表示1--i的异或值,那么i...j的异或值就是sum[j] ^ sum[i - 1]

    所以原问题转化为在一个数组中,任选两个数,异或值 >= k

    首先所有数字 <= 1e9

    那么前缀异或值 <= 2^31 - 1

    那么用int就够了,从30位开始插入字典树,(1 << 31)是溢出的

    查找的时候,分两类

    1、当前的位置中k的二进制位是0,就是第15位,如果k的二进制位是0,那么往反方向走字典树的子树总是可以得,这个时候只需要加上去子树大小即可。

    2、如果那一位k是1,我们没法马上判断贡献,那么只能往反方向贪心走字典树。

    注意的就是叶子节点有可能没走到,需要最后加上来。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 1e6 + 20;
    const int N = 2;
    int a[maxn];
    int sum[maxn];
    int n, k;
    struct node {
        struct node *pNext[N];
        int cnt;
    }tree[maxn * 40];
    int t;
    struct node * create() {
        struct node *p = &tree[t++];
        for (int i = 0; i < N; ++i) {
            p->pNext[i] = 0;
        }
        p->cnt = 0;
        return p;
    }
    void insert(struct node **T, int val) {
        struct node *p = *T;
        if (p == NULL) {
            p = *T = create();
        }
        for (int i = 30; i >= 0; --i) {
            int id = (val & (1 << i)) > 0;
            if (p->pNext[id] == NULL) {
                p->pNext[id] = create();
            }
            p = p->pNext[id];
            p->cnt++;
        }
        return ;
    }
    LL find(struct node *T, int val) {
        struct node *p = T;
        LL ans = 0;
        if (p == NULL) return ans;
        for (int i = 30; i >= 0; --i) {
            int id = (val & (1 << i)) > 0;
            int id_k = (k & (1 << i)) > 0;
            if (id_k == 0) {
                if (p->pNext[!id] != NULL)
                    ans += p->pNext[!id]->cnt; //这边的树全部都可以
                if (p->pNext[id] == NULL) return ans;
                p = p->pNext[id]; //如果走到了叶子节点,我这里return了,不会重复增加
            } else { //id_k = 1
                if (p->pNext[!id] == NULL) return ans;
                p = p->pNext[!id];
            }
        }
        return ans + p->cnt; //叶子节点有可能没算到,参考样例1
    }
    void work() {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            sum[i] = sum[i - 1] ^ a[i];
    //        cout << sum[i] << " ";
        }
    //    printf("%d
    ", 1 << 30);
        struct node *T = NULL;
    
        insert(&T, sum[1]);
        LL ans = 0;
        for (int i = 2; i <= n; ++i) {
            ans += find(T, sum[i]);
            insert(&T, sum[i]);
    //        cout << find(T, sum[i]) << endl;
        }
        for (int i = 1; i <= n; ++i) ans += sum[i] >= k;
        cout << ans << endl;
        return;
    }
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    Swift新手教程3-字符串String
    BZOJ 2006 NOI2010 超级钢琴 划分树+堆
    Makefile学习(一)[第二版]
    leetcode 26 -- Remove Duplicates from Sorted Array
    谈谈我眼中的泛型
    oracle表空间查询维护命令大全之三(暂时表空间)史上最全
    超大表盘手表 : 超大表盘手表图片及搭配,超大表盘手表价格-美丽说
    Linux下安装Python3.3.0
    朝阳公园朝阳公园水下猎人潜水艇团购:水下猎人潜艇观光+水下梭镖打鱼套票!体验前所未有的水下休闲娱乐,探寻海底世界-聚齐北京团购
    隐形选购指南_亿超眼镜网
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5884755.html
Copyright © 2011-2022 走看看