本文已参与「新人创作礼」活动,一起开启掘金创作之路。
给定一个长度为的数组,一个整数,求区间中有多少,满足 传送门
分析
先考虑暴力 求 就是要求,异或前缀下的 固定起点,暴力往后走 假如走到的位置,计算,如果等于的话就加,依次计算,复杂度 再想想优化 上面复杂度显然不行,考虑固定左端点,拓展右端点的时候直接把所有以右端点结尾的答案都计算出来 如果当前右端点走到了位置,因为我们要找到异或后等于的值,既然要让能做出贡献,那么此时一定在前面计算的某一个左端点,存在 ,推出,也就是说,所有以为结尾的区间异或等于的贡献,就是前面计算的所有,值等于的数量
考虑添加一个数,计数器,答案 考虑删除一个数,计数器,答案
注意细节,题目要求是是合法的,所以得先计数器改变,再统计答案个数
那么计算一个区间内满足条件的个数,时间复杂度就是了
接下来就是,如何求出多个区间的问题? 普通莫队就能够解决 添加,删除的操作上面应该已经说清楚了
代码
//CF617
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
int arr[MAX_N];
int cnt[MAX_N<<1];
int mo = 0;
int ans[MAX_N];
void add(int x) {
mo += cnt[arr[x]^K];
++cnt[arr[x]];
}
void del(int x) {
--cnt[arr[x]];
mo -= cnt[arr[x]^K];
}
int block;
int idb(int x) {
return x/block;
}
struct Qr {
int l, r, id;
bool operator < (const Qr& B) const {
return idb(l) ^ idb(B.l)? l < B.l : (idb(l)&1) ? r < B.r : r > B.r;
}
}qr[MAX_N];
void solve(){
sc("%lld%lld%lld", &N, &M, &K);
block = max(sqrt(N), sqrt((N*N)/M));
for (int i = 1; i <= N; ++i) {
sc("%lld", &arr[i]);
arr[i] ^= arr[i-1];
}
for (int i = 1; i <= M; ++i) {
sc("%lld%lld", &qr[i].l, &qr[i].r);
--qr[i].l;
qr[i].id = i;
}
sort(qr+1, qr+1+M);
int l = 1, r = 0;
mo = 0;
for (int i = 1; i <= M; ++i) {
while (l > qr[i].l) add(--l);
while (r < qr[i].r) add(++r);
while (l < qr[i].l) del(l++);
while (r > qr[i].r) del(r--);
ans[qr[i].id] = mo;
}
for (int i = 1; i <= M; ++i) {
pr("%lld\n", ans[i]);
}
}
signed main()
{
#ifndef ONLINE_JUDGE
//FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}