Codeforces 617E XOR and Favorite Number

题目链接

https://codeforces.com/contest/617/problem/E

题目大意

给你一个长度为 N 的序列和 M 个查询,每个查询问你区间 [L , R] 中有多少子区间异或和为 K

解题思路

莫队 + 前缀异或和

设 sum[i] 为序列的前 i 个数的异或和,那么根据异或性质可知一段区间 X , Y的异或和就为 sum[y] ^ sum[x - 1]

于是可以将询问转换为区间 [L , R] 中有多少对 X , Y 使得 sum[y]  ^ sum[x - 1] = k

设 cnt[i] 表示异或和 i 出现的次数,那么常规的做法就是对于每次询问从 L 遍历到 R 一边更新答案一遍记录前缀异或和

map<int , int>cnt;
for(int i = 1 ; i <= m ; i ++)
{
    int ans = 0 ;
    cnt.clear();
    cnt[0] = 1;
    for(int j = q[i].l; j <= q[i].r ; j ++)
    {
        int now = sum[q[i].l - 1]; //把 [1 - (L - 1)] 的异或和去掉
        ans += cnt[sum[j] ^ k ^ now];
        cnt[sum[j] ^ now] ++ ;
    }
    cout << ans << '\n';
}

显然这么做复杂度是肯定不行的,而题目又不涉及修改区间等操作,所以可以套个莫队离线操作

AC_Coder

#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false)
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define int long long
using namespace std;
const int N = 2e5 + 10;
struct Q{
    int l , r , id;
}q[N];
int a[N] , pos[N] , sum[N] , ans[N] ;
unordered_map<int , int>cnt;
int n , m , k , sz , l = 1 , r , res;
bool cmp(Q a , Q b)
{
    if(pos[a.l] == pos[b.l]) return a.r < b.r;
    return pos[a.l] < pos[b.l];
}
void Add(int x)
{ 
    res += cnt[sum[x] ^ k];
    cnt[sum[x]] ++ ;
}
void Sub(int x)
{
    cnt[sum[x]] -- ;
    res -= cnt[sum[x] ^ k];
}
signed main()
{
    ios;
    cin >> n >> m >> k;
    sz = sqrt(n);
    rep(i , 1 , n) cin >> a[i] , sum[i] = sum[i - 1] ^ a[i] , pos[i] = i / sz;
    rep(i , 1 , m)
    {
        cin >> q[i].l >> q[i].r;
        q[i].id = i;    
    } 
    cnt[0] = 1;
    sort(q + 1 , q + 1 + m , cmp);
    rep(i , 1 , m)
    {
        while(q[i].l < l) -- l , Add(l - 1);
        while(q[i].l > l) Sub(l - 1) , l ++;
        while(q[i].r > r) Add(++ r);
        while(q[i].r < r) Sub(r --);
        ans[q[i].id] = res;
    }
    rep(i , 1 , m) cout << ans[i] << '\n';
    return 0;
}
posted @ 2020-06-01 17:13  GsjzTle  阅读(179)  评论(0编辑  收藏  举报