1 条题解
-
0
好题。
如何求出任意一段的区间异或值是个问题。
如果我们要求,那么显然是可以表示为$(a_1\ xor\ a_2\ xor...xor\ a_{i-1})xor(a_1\ xor\ a_2\ xor...xor\ a_j)$。
所以如果用前缀异或数组的话这道题就变成了“求中有多少个数对满足”。
考虑用莫队离线计算。
由于的话就有,所以每次加入一个数字后,和异或后等于的数字都可以算入答案。也就是说,我们只要知道区间内有多少个数字,就可以知道答案要加上几。删除时同理。
用表示数字在区间内出现的次数。然后就是裸的莫队了。
#include <cmath> #include <cstdio> #include <string> #include <algorithm> using namespace std; typedef long long ll; const int N=100010,M=1200010; int n,m,k,l,r,T,cnt[M],a[N],pos[N]; ll ans; struct Ask { int l,r,id; ll ans; }ask[N]; ll write(ll x) { if (x>9) write(x/10); putchar(x%10+48); } bool cmp1(Ask x,Ask y) //按照块来排序 { if (pos[x.l]<pos[y.l]) return 1; if (pos[x.l]>pos[y.l]) return 0; return x.r<y.r; } bool cmp2(Ask x,Ask y) { return x.id<y.id; } void add(int x) { ans+=(ll)cnt[a[x]^k]; //加上数字a[x]^k的个数。 cnt[a[x]]++; } void del(int x) { cnt[a[x]]--; ans-=(ll)cnt[a[x]^k]; } int main() { scanf("%d%d%d",&n,&m,&k); T=(int)sqrt(n); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); a[i]^=a[i-1]; pos[i]=(i-1)/T+1; } for (int i=1;i<=m;i++) { scanf("%d%d",&ask[i].l,&ask[i].r); ask[i].l--; ask[i].id=i; } sort(ask+1,ask+1+m,cmp1); cnt[0]=1; for (int i=1;i<=m;i++) { for (;l<ask[i].l;l++) del(l); for (;l>ask[i].l;l--) add(l-1); for (;r<ask[i].r;r++) add(r+1); for (;r>ask[i].r;r--) del(r); ask[i].ans=ans; //直接记录答案 } sort(ask+1,ask+1+m,cmp2); for (int i=1;i<=m;i++) write(ask[i].ans),putchar(10); return 0; }
- 1
信息
- ID
- 1337
- 时间
- 4000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 61
- 已通过
- 26
- 上传者