Educational Codeforces Round 12 E. Beautiful Subarrays

本文介绍了一种通过构建前缀异或和与Trie树来解决寻找数组中异或和大于等于特定值k的子数组数量的问题。文章详细阐述了算法步骤,并提供了完整的C++实现代码。

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


题意:给以一个序列,问你这个序列有多少个连续子序列的异或和大于等于k。


分析:对序列求出前缀异或和后,问题转化为求序列两个元素的异或和大于等于k,我们把所有数扔进一棵tire中,每次加入新数后在tire中查找一次k,如果当前k的位置为0,那么当前节点的右儿子下的所有数都可以记入答案,最后记得加上异或和等于k的数。


#include <cstdio>
#include <iostream>
#define MAX 30*1000000
using namespace std;
long long ans; 
int n,k,a[1000001];
struct trie
{
	int ch[MAX][2],tot;
	long long val[MAX];
	void build()
	{
		val[0] = 0;
		ans = 0;
		tot = 1;
	}
	void insert(int s)
	{
		int u = 0;
		for(int i = 30;i >= 0;i--)
		{
			int v = ((1<<i) & s) ? 1 : 0;
			if(!ch[u][v]) ch[u][v] = tot++;
			u = ch[u][v];
			val[u]++;
		}
	}
	void find(int s)
	{
		int u = 0;
		for(int i = 30;i >= 0;i--)
		{
			int v = ((1<<i) & s) ? 1 : 0;
			if(((1<<i) & k) == 0) 
			{
				ans += val[ch[u][1 xor v]];
				u = ch[u][v];
			}
			else u = ch[u][1 xor v];
			if(!u) break; 
		}
		ans += val[u];
	}
} tree;
int main()
{
	tree.build();
	tree.insert(0);
	scanf("%d%d",&n,&k);
	for(int i = 1;i <= n;i++) 
	{
		scanf("%d",&a[i]);
		a[i] = a[i] ^ a[i-1];
		tree.find(a[i]);
		tree.insert(a[i]);
	}
	cout<<ans<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值