题目地址:http://codeforces.com/problemset/problem/617/E
题意;给了一个数组,要求询问m次,询问给的区间里有多少子区间Xor后等于k.
这题纠结了一天,经过巨巨的指导,终于略懂了,今天来做一下笔记。
一般区间问题都会涉及到前缀和或后缀和之类的,当然这题也不例外。假设现在有一个前缀异或和数组sum【】,区间【L,R】的异或为sum【R】^sum【L-1],。
求有多少子区间子异或和为k,如【a,b】区间异或为k, 即sum【a-1】^sum【b]=k; sum【b】^k=sum【a-1】;包含区间【a,b】且异或和为k的区间个数为num【sum[a-1] 】=num[sum[b]^k],因此我们只需记录num[sum[b]^k]就行。这里需要注意一下左边界,我们统计num【sum[a-1]】,所以需要先把num【sum【a-1]】++;我们巧妙的把左边界减1。
莫队算法,具体见:http://blog.anudeep2011.com/
题意;给了一个数组,要求询问m次,询问给的区间里有多少子区间Xor后等于k.
这题纠结了一天,经过巨巨的指导,终于略懂了,今天来做一下笔记。
一般区间问题都会涉及到前缀和或后缀和之类的,当然这题也不例外。假设现在有一个前缀异或和数组sum【】,区间【L,R】的异或为sum【R】^sum【L-1],。
求有多少子区间子异或和为k,如【a,b】区间异或为k, 即sum【a-1】^sum【b]=k; sum【b】^k=sum【a-1】;包含区间【a,b】且异或和为k的区间个数为num【sum[a-1] 】=num[sum[b]^k],因此我们只需记录num[sum[b]^k]就行。这里需要注意一下左边界,我们统计num【sum[a-1]】,所以需要先把num【sum【a-1]】++;我们巧妙的把左边界减1。
莫队算法,具体见:http://blog.anudeep2011.com/
详细见代码
// 复杂度O(sqrt(n)) #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<stack> #include<vector> #include<cmath> #include<string> using namespace std; typedef long long LL; #define INF 0x3f3f3f3f const int maxn=1e6+100; #define PI acos(-1.0) #define lowbit(x) x&-x struct node { int a,b; int id; }; node Q[maxn]; int unit,n,m,k; LL ans[maxn]; int num[2*maxn]; int A[maxn]; bool cmp(node a,node b)//区间分块排序 { if(a.a/unit==b.a/unit) return a.b<b.b; else return a.a<b.a; } void work() { int i,j; memset(num,0,sizeof(num)); int L=1; int R=0; LL temp=0; for(i=0;i<m;i++) { while(R<Q[i].b) { R++; temp+=num[A[R]^k]; num[A[R]]++; } while(R>Q[i].b) { num[A[R]]--; temp-=num[A[R]^k]; R--; } while(L>Q[i].a-1) { L--; temp+=num[A[L]^k]; num[A[L]]++; } while(L<Q[i].a-1) { num[A[L]]--; temp-=num[A[L]^k]; L++; } ans[Q[i].id]=temp; } } int main() { scanf("%d%d%d",&n,&m,&k); int i,j; A[0]=0; for(i=1;i<=n;i++) { scanf("%d",&A[i]); A[i]^=A[i-1]; //处理前缀异或和 } for(i=0;i<m;i++) { scanf("%d%d",&Q[i].a,&Q[i].b); Q[i].id=i; } unit=(int)ceil(sqrt((double)n)); sort(Q,Q+m,cmp); work(); for(i=0;i<m;i++) { printf("%I64d\n",ans[i]); } return 0; }