Educational Codeforces Round 12 E. Beautiful Subarrays(区间异或+字典树)

题目链接
在这里插入图片描述
思路:首先区间异或有一个性质s【l-1】^s【r】=s【l。。。。r】,所以我们考虑异或前缀和,我们从k的每位二进制来考虑,在已经构造好的字典树中,如果k的第pos位是0,那么我们看看当前字典树能不能走相反的方向,能的话就能把这一位异或为1,就会对他们产生贡献,加上经过这条边的个数就行了,如果第pos位是1的话我们最低要求也得保障我们字典树这一位异或起来是1才行,不然如果是0的话就不可能会比k大了,然后逐步更新字典树就行,不过这里的k要减1才行,不然会漏掉与k相等的情况。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5;
ll cnt=0,k,tree[maxn*20][2],sum[maxn*20],a[maxn],ans;
void insert(ll x)
{
	int u=0;
	for(int i=31;i>=0;--i)
	{
		int t=(((1LL<<i)&x)?1:0);
		if(!tree[u][t]) tree[u][t]=++cnt;
		sum[tree[u][t]]++;
		u=tree[u][t];
	}
}
void query(ll x)
{
	int u=0;
	for(int i=31;i>=0;--i)
	{
		int t=(((1LL<<i)&x)?1:0),s=(((1LL<<i)&k)?1:0);
		if(s==0) {
			if(tree[u][t^1]) ans+=sum[tree[u][t^1]];
			u=tree[u][t];
		}
		else {
			if(tree[u][t^1]) u=tree[u][t^1];
			else u=0;
		}
		if(!u) break;
	}
}
int main()
{
	int n;
	scanf("%d%lld",&n,&k);
	k--;
	insert(0);
	for(int i=1;i<=n;++i) 
	{
		scanf("%lld",&a[i]);
		a[i]^=a[i-1];
		query(a[i]);
		insert(a[i]);
	}
	printf("%lld\n",ans);
}
发布了283 篇原创文章 · 获赞 0 · 访问量 7314

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105057734
今日推荐