Codeforces ~ 617E ~ XOR and Favorite Number (前缀和 + 莫队)

题意

n个数,m次询问,每次问[L,R]区间内又多少个(i,j)满足a[i]^a[i+1]...^a[j]==k?

思路

求前缀异或和,那么pre[L-1]^pre[R]=a[L]^...^a[R]。假设pre[L-1]^pre[R]=k,则有pre[L-1]=pre[R]^k。所以我们用cnt[x]表示当前区间内异或 k 为 x 的值有多少个。

然后就可以用莫队了。区间增加1,对答案的贡献增加cnt[a[x]^k]的贡献,同时cnt[a[x]^k]++。

区间减少1,对答案的贡献减少了cnt[a[x]^k]的贡献,同时cnt[a[x]^k]--。

由于我们用的是前缀和,所以当我们L区间变化的时候,对答案的贡献增加或减少的是 pre[L-1]^k 的值,一定要注意。

还有就是什么都不选的时候异或和为0,所以初始化cnt[0]=1。

PS:

有点SB了,++,--用的导致代码难懂。。。

a[(l++)-1],先把a[l-1]传过去,然后再l++。

a[(--l)-1],先l--,然后再把a[l-1]传过去。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+5;
typedef long long LL;
int n, m, k, a[MAXN];
struct Query
{
    int l, r, id;
    LL ans;
}q[MAXN];
int block, pos[MAXN], l, r;
LL cnt[MAXN*10], ans;
void update(int x, int d)
{
    if (d == 1) ans += cnt[x^k], cnt[x]++;
    if (d == -1) cnt[x]--, ans -= cnt[x^k];
}
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    block = sqrt(n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        a[i] ^= a[i-1];
        pos[i] = (i-1)/block+1;
    }
    for (int i = 0; i < m; i++) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
    sort(q, q+m, [](Query A, Query B){ return pos[A.l]!=pos[B.l]?A.l<B.l:A.r<B.r; });
    cnt[0] = 1;
    l = 1, r = 0, ans = 0;
    for (int i = 0; i < m; i++)
    {
        while (l < q[i].l) update(a[(l++)-1], -1);
        while (l > q[i].l) update(a[(--l)-1], 1);
        while (r < q[i].r) update(a[++r], 1);
        while (r > q[i].r) update(a[r--], -1);
        q[i].ans = ans;
    }
    sort(q, q+m, [](Query A, Query B){ return A.id < B.id; });
    for (int i = 0; i < m; i++) printf("%lld\n", q[i].ans);
    return 0;
}
/*
6 2 3
1 2 1 1 0 3
1 6
3 5
*/

猜你喜欢

转载自blog.csdn.net/zscdst/article/details/81123150