CF617/E XOR and Favorite Number
题目链接:http://codeforces.com/contest/617/problem/E
题意:给出一个长度为n(1e5)的序列,有m(1e5)次操作,每次操作选择一个L-R区间,然后输出符合条件的i,j的个数:L<i<j<R,ai^a------^aj=k,k是一个给定的值
题解:莫队可做,首先,求一个前缀异或和,如果求ai^……^a[j]的值,那么sum[j]^sum[i-1]。莫队的思想是已知道[L,R]的值,可以在O(1)的时间内算出[L-1,R],[L,R-1]等等的值,
好,现在如果我们维护[L-R]区间,所有{sum[L-1],sum[R-1]}和{sum[L,sum[R]},去除中间重复的部分,然后维护{sum[L-1],sum[R]},这样就方便维护所有的值了。
另外呢,优于是异或,所以呢,中间异或的值很可能会大于1e6,所以标记数组要开的大一点。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = (1 << 20) - 1; int A[maxn], pos[maxn], sz = 320; LL num[maxn], Ans[maxn], ans = 0; struct Edge { int l, r, id; } E[maxn]; bool cmp (Edge a, Edge b) { if(pos[a.l] == pos[b.l]) return a.r < b.r; return pos[a.l] < pos[b.l]; } int L = 1, R = 0; int N, M, k; void add(int x) { ans += num[A[x] ^ k]; num[A[x]]++; } void det(int x) { num[A[x]]--; ans -= num[A[x] ^ k]; } int main () { scanf("%d %d %d", &N, &M, &k); for(int i = 1; i <= N; i++) { scanf("%lld", &A[i]); A[i] ^= A[i - 1]; pos[i] = i / sz; } for(int i = 1; i <= M; i++) { scanf("%d %d", &E[i].l, &E[i].r); E[i].id = i; } num[0] = 1; sort(E + 1, E + 1 + M, cmp); for(int i = 1; i <= M; i++) { while(L < E[i].l) { det(L - 1); L++; } while(L > E[i].l) { L--; add(L - 1); } while(R < E[i].r) { R++; add(R); } while(R > E[i].r) { det(R); R--; } Ans[E[i].id] = ans; } for(int i = 1; i <= M; i++) printf("%lld\n", Ans[i]); return 0; }
想的太多,做的太少。