Beautiful Subarrays

E. Beautiful Subarrays

One day, ZS the Coder wrote down an array of integers a with elements a1,  a2,  ...,  an.

A subarray of the array a is a sequence al,  al  +  1,  ...,  ar for some integers (l,  r) such that 1  ≤  l  ≤  r  ≤  n. ZS the Coder thinks that a subarray of a is beautiful if the bitwise xor of all the elements in the subarray is at least k.

Help ZS the Coder find the number of beautiful subarrays of a!

Input

The first line contains two integers n and k (1 ≤ n ≤ 106, 1 ≤ k ≤ 109) — the number of elements in the array a and the value of the parameter k.

The second line contains n integers ai (0 ≤ ai ≤ 109) — the elements of the array a.

Output

Print the only integer c — the number of beautiful subarrays of the array a.

Examples
Input
3 1
1 2 3
Output
5
Input
3 2
1 2 3
Output
3
Input
3 3
1 2 3
Output
2

题意:题目的意思是给你n个非负整数的数组.求这个数组中有多少个子区间,区间的异或和至少是k

题解:看到异或和,就联想到了字典树了...blabla 枚举数组,对于第i个数,求出有多少个以第i个数为结尾的区间满足区间异或和至少是k.很自然,对于一个数,如何判断

它是否大于等于k,这个可以通过比较他们的二进制位.因为整数最大为1e9,所以最多比较31次.接下来就分类讨论下: 对于第j个二进制位,如果k& (1<<j) > 0,则要保证以

第i个数结尾的区间异或和在第j个二进制位也要为1.反过来为0.知道这个后,就可以通过异或前缀和来找出有多少个区间满足这种情况.但是如果纯粹枚举时间复杂度是n^2 *

30的,所以可以通过一种数据结构字典树来优化复杂度,时间复杂度降为n * 30.这样题目就可以在1s以内跑过去了,题目给了3s,还是挺良心的.


AC代码:

#include <iostream>
#include <vector>
#include <map>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

typedef long long ll;
const int N = 3e7 + 5;
int tot;

struct Node
{
    int val;
    int next[2];
    void init()
    {
        val = 0;
        memset(next,0,sizeof next);
    }
}tree[N];

void Insert(int x)
{
    int pos = 0;
    for(int i = 30; i >= 0; --i)
    {
        int v = (x & (1 << i)) ? 1 : 0;
        if(!tree[pos].next[v])
        {
            tree[++tot].init();
            tree[pos].next[v] = tot;
        }
        pos = tree[pos].next[v];
        ++tree[pos].val;
    }
}

int Find(int x,int k)
{
    int cnt,pos;
    cnt = pos = 0;
    for(int i = 30; i >= 0; --i)
    {
        int v = (x & (1 << i)) ? 1 : 0;
        if(k & (1 << i))
        {
            pos = tree[pos].next[v ^ 1];
        }
        else
        {
            int tp = tree[pos].next[v ^ 1];
            pos = tree[pos].next[v];
            cnt += tree[tp].val;
        }
        if(pos == 0)
            break;
        if(i == 0)
            cnt += tree[pos].val;
    }
    return cnt;
}

void solve()
{
    int n,k,temp,x;
    ll ans = 0;
    scanf("%d %d",&n,&k);
    tot = temp = 0;
    tree[tot].init();
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d",&x);
        Insert(temp);
        temp ^= x;
        ans += Find(temp,k);
    }
    cout << ans << endl;
}


int main()
{
    solve();
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值