Codeforces 617E:XOR and Favorite Number(莫队算法)
http://codeforces.com/problemset/problem/617/E
题意:给出n个数,q个询问区间,问这个区间里面有多少个区间[i,j]可以使得ai^ai+1^...^aj = k。
思路:根据xor的性质,可以处理出前缀异或和sum[],那么要使结果等于k,就是sum[i-1]^sum[j] == k,即sum[j]^k == sum[i-1],那么用一个数组cnt[]存储对于每一个sum[]的数量。然后用莫队算法做。莫队算法是一种离线处理区间问题的算法,在我看来是将询问通过分块排序成一个可以暴力处理的序列,让暴力的复杂度尽量的低。只有O(n*sqrt(n))的复杂度。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <string> 7 #include <iostream> 8 #include <stack> 9 #include <map> 10 #include <queue> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 #define N 100010 15 #define INF 0x3f3f3f3f 16 struct node { 17 int l, r, id; 18 LL ans; 19 } q[N*10]; 20 int sum[N], kuai, k; 21 LL cnt[N*20]; 22 23 bool cmp1(const node &a, const node &b) { 24 if(a.l / kuai != b.l / kuai) return a.l / kuai < b.l / kuai; // 根据块的编号排序 25 return a.r < b.r; // 块内按照r值排序 26 } 27 28 bool cmp2(const node &a, const node &b) { 29 return a.id < b.id; 30 } 31 32 int main() 33 { 34 int n, m, num, L, R; 35 LL s = 0; 36 scanf("%d%d%d", &n, &m, &k); 37 for(int i = 1; i <= n; i++) { 38 scanf("%d", &num); sum[i] = sum[i-1] ^ num; 39 } 40 for(int i = 1; i <= m; i++) { 41 scanf("%d%d", &q[i].l, &q[i].r); 42 q[i].id = i; q[i].l--; 43 } 44 kuai = sqrt(n); 45 sort(q + 1, q + 1 + m, cmp1); 46 L = 1; R = 0; 47 for(int i = 1; i <= m; i++) { 48 int l = q[i].l, r = q[i].r; 49 while(L < l) { 50 cnt[sum[L]]--; 51 s -= cnt[sum[L]^k]; 52 L++; 53 } 54 while(L > l) { 55 L--; 56 s += cnt[sum[L]^k]; 57 cnt[sum[L]]++; 58 } 59 while(R < r) { 60 R++; 61 s += cnt[sum[R]^k]; 62 cnt[sum[R]]++; 63 } 64 while(R > r) { 65 cnt[sum[R]]--; 66 s -= cnt[sum[R]^k]; 67 R--; 68 } 69 q[i].ans = s; 70 } 71 sort(q + 1, q + 1 + m, cmp2); 72 for(int i = 1; i <= m; i++) printf("%lld\n", q[i].ans); 73 return 0; 74 }