您的位置:首页 > 其它

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

2016-09-24 22:26 246 查看
题意:

求规模为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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: