Educational Codeforces Round 12 E. Beautiful Subarrays 预处理前缀+字典树优化★ ★

题意:

求规模为1e6数组中,连续子串xor值大于等于k值的子串数;

思路:

xor为和模2的性质,所以先预处理之后,可以枚举这种确实子串区间的方法为O(n^2);

优化?把每一个前缀xor扔到二叉树中,从根节点出发,以高位前缀值的二进制数构造一颗二叉树,这样就可以在构造的时候,实现对子树节点个数的求解;之后在线求解到当前节点的可选的前缀xor的个数,

即以k为主线

如果当前位k为1,则在前缀二叉树中只能找和当前节点xor出结果为1的节点,并且这个节点的num值不能加到结果中;

如果是当前位k为0,则直接加上xor结果为1的节点个数(num),方向不变;

注:最后一个叶子节点不能求到,要在最后加上叶子节点的个数


#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF  0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-9
#define maxn 1000100
#define MOD 1000000007

const int MAXN = 11234567;
long long num[MAXN];
int tot = 1,d[MAXN][2],n,k;
void update(int x)
{
    int p = 1;
    for(int i = 30; i >= 0; i--)
    {
        if(d[p][(x>>i)&1] == 0)
            d[p][(x>>i)&1] = ++tot;
        p = d[p][(x>>i)&1];
        num[p]++;
    }
}
long long solve(int x)
{
    long long ans = 0;
    int p = 1;
    for(int i = 30; i >= 0; i--)
    {
        if((k>>i)&1)
            p = d[p][1^((x>>i)&1)];
        else
        {
            ans += num[d[p][1^((x>>i)&1)]];
            p = d[p][0^((x>>i)&1)];
        }
    }
    return ans + num[p];
}
int main()
{
    int t;
    //scanf("%d",&t);
    while(scanf("%d%d",&n,&k) != EOF)
    {
        int prefix = 0,x;
        long long ans = 0;
        memset(d,0,sizeof(d));
        memset(num,0,sizeof(num));
        for(int i = 0; i < n; i++)
        {
            update(prefix);
            scanf("%d",&x);
            prefix ^= x;
            ans += solve(prefix);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值