CodeForces - 617E XOR and Favorite Number (莫队)

题链:http://codeforces.com/contest/617/problem/E

题意:对于一个区间[L,R],问有多少子区间[l,r],a[l] ^ a[l+1] ^ a[l+2] ^  ...  ^ a[r] == k ?

思路:首先,先解决求 a[l] ^ a[l+1] ^ a[l+2] ^  ...  ^ a[r] , 这里用前缀思想,即pre[l-1]^pre[r]。现在,我们维护一个num数组,num[k]代表pre[i]==k的个数。考虑加入一个数,那么,答案要先加上num[k^pre[i]],然后num[pre[i]]++;考虑删除一个数,那么先num[pre[i]]--,然后答案减去num[k^pre[i]]。注意一个询问区间[ql,qr],要变为[ql-1,qr]。感性的理解就是前缀和,理性的理解就是要加上以ql为左端点的子区间,因为以ql为左端点的子区间异或和时,异或的是pre[ql-1]。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+10;
int n,m,k,a[N];
struct node{
	int l,r,id;
}q[N];
int base,belong[N];
int num[N<<1],now=0;
ll ans[N],sum=0;
void del(int x){
	--num[a[x]];
	sum-=num[k^a[x]];
}
void add(int x){
	sum+=num[k^a[x]];
	++num[a[x]];	
}
bool cmp(node a,node b){
	return (belong[a.l]^belong[b.l])?belong[a.l]<belong[b.l]:((belong[a.l]&1)?a.r<b.r:a.r>b.r);
}
int main(void){
	scanf("%d%d%d",&n,&m,&k);
	base=ceil(sqrt(1.0*n));
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		a[i]^=a[i-1];
		belong[i]=i/base;
	}	
	for(int i=1;i<=m;i++)
		scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
	sort(q+1,q+1+m,cmp);
	int l=1,r=0;
	for(int i=1;i<=m;i++){
		int ql=q[i].l-1,qr=q[i].r;
		while(l<ql) del(l++);
		while(l>ql) add(--l);
		while(r>qr) del(r--);
		while(r<qr) add(++r);
		ans[q[i].id]=sum;
	}
	for(int i=1;i<=m;i++)
		printf("%lld\n",ans[i]);
	return 0;	
} 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值