题目描述
已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在al,al+1,…,ar区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足ax⊕ax+1⊕⋯⊕ay=k的x,y有多少组。
输入
输入第一行为3个整数n,m,k。第二行为空格分开的n个整数,即a1,a2,…,an。接下来m行,每行两个整数lj,rj,代表一次查询。
输出
输出共m行,对应每个查询的计算结果。
样例输入
4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4
样例输出
4
2
1
2
1
提示
对于30%的数据,1≤n,m≤1000。
对于100%的数据,1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n。
使用莫队算法。
这里只讲一下细节和实现问题。
初始化cnt[0] = 1:如果只给你一个数据ai = 1,和k = 1,怎么计算?就是1^0 = 1,就是说使用了数字0来参与异或,所以初始化cnt[0] = 1.
同时,因为多使用了数字0,导致使用莫队模板时左端点 L-1
还有就是col [i] 中存储的是前i项异或的值
#include<bits/stdc++.h> using namespace std; const int M = 1e5 + 5; struct Node { int l,r,id; }q[M]; int col[M],cnt[M],ans[M],pos[M],block,tot; int n,m,k; bool cmp(Node a, Node b) { return pos[a.l]==pos[b.l] ? a.r<b.r : a.l<b.l; } void add(int x) { tot += cnt[col[x]^k]; cnt[col[x]]++; } void sub(int x) { tot -= cnt[col[x]^k]; cnt[col[x]]--; } int main() { ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr); //加快cin,cout速度,同时endl换成'\n' cin>>n>>m>>k; block = sqrt(n); for(int i = 1; i <= n; i++) { cin>>col[i]; col[i] ^= col[i-1]; pos[i] = i/block + 1; } for(int i = 1; i <= m; i++) { cin>>q[i].l>>q[i].r; q[i].id = i; } sort(q+1,q+1+m,cmp); int l = 1, r = 0; cnt[0] = 1; for(int i = 1; i <= m; i++) { while(l>q[i].l) l--,add(l-1); while(l<q[i].l) sub(l-1),l++; while(r>q[i].r) sub(r--); while(r<q[i].r) add(++r); ans[q[i].id] = tot; } for(int i = 1; i <= m; i++) cout<<ans[i]<<'\n'; return 0; }