zoukankan      html  css  js  c++  java
  • Codeforces Round #340 (Div. 2) E. XOR and Favorite Number 【莫队算法 + 异或和前缀和的巧妙】

    任意门:http://codeforces.com/problemset/problem/617/E

    E. XOR and Favorite Number

    time limit per test
    4 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Bob has a favorite number k and ai of length n. Now he asks you to answer m queries. Each query is given by a pair li and ri and asks you to count the number of pairs of integers i and j, such that l ≤ i ≤ j ≤ r and the xor of the numbers ai, ai + 1, ..., aj is equal to k.

    Input

    The first line of the input contains integers nm and k (1 ≤ n, m ≤ 100 000, 0 ≤ k ≤ 1 000 000) — the length of the array, the number of queries and Bob's favorite number respectively.

    The second line contains n integers ai (0 ≤ ai ≤ 1 000 000) — Bob's array.

    Then m lines follow. The i-th line contains integers li and ri (1 ≤ li ≤ ri ≤ n) — the parameters of the i-th query.

    Output

    Print m lines, answer the queries in the order they appear in the input.

    Examples

    input
    6 2 3
    1 2 1 1 0 3
    1 6
    3 5
    output
    7
    0
    input
    5 3 1
    1 1 1 1 1
    1 5
    2 4
    1 3
    output
    9
    4
    4
    Note

    In the first sample the suitable pairs of i and j for the first query are: (1, 2), (1, 4), (1, 5), (2, 3), (3, 6), (5, 6), (6, 6). Not a single of these pairs is suitable for the second query.

    In the second sample xor equals 1 for all subarrays of an odd length.

    题目大意:

    有一串长度为 N 的数列,M次查询 ( l,r )内有多少对 ( i, j )使得 ai ^ ai+1 ^ ... ^ aj = K;

    解题思路:

    这里的区间查询是离线的,可以用传说中的莫队算法(优雅而华丽的暴力算法)。

    异或的题目有一个很巧妙的地方就是利用 a^b^a = b 这个性质。

    这道题目我们也要预处理一下 sum(i) 前 i 个数的异或和, 那么 ai ^ ai+1 ^ ... ^ aj = sum( i - 1) ^ sum( j ) 了。

    接下来我们就可以按照查询的区间用莫队算法遍历一遍,同时记录当前区间某个前缀和的出现次数;

    根据 sum( i - 1) ^ sum( j ) = K ,K  ^ sum( i - 1 ) = sum( j ) || K ^ sum( j ) = sum( i - 1) ,由符合条件的前缀和次数来推出符合条件的( i,j )的个数啦。

    Tip:

    听了大神的课,这道题有两个坑:

    1、答案的数据的数据范围是爆 int 的;

    2、虽然是1e6 的 K,但异或的结果要大于 1e6 ;

    AC code:

     1 #include <bits/stdc++.h>
     2 #define LL long long int
     3 using namespace std;
     4 const int MAXN = 1<<20;
     5 
     6 struct node
     7 {
     8     int l, r, id;  //区间和查询编号
     9 }Q[MAXN];       //记录查询数据(离线)
    10 
    11 int pos[MAXN];  //记录分块
    12 LL ans[MAXN];   //记录答案
    13 LL flag[MAXN];  //维护前缀异或和出现的次数
    14 int a[MAXN];    //原本数据
    15 int L=1, R;     //当前区间的左右结点
    16 LL res;         //储存当前区间的值
    17 int N, M, K;
    18 bool cmp(node a, node b)     //排序
    19 {
    20     if(pos[a.l]==pos[b.l]) return a.r < b.r;  //只有左结点在同一分块才排右结点
    21     return pos[a.l] < pos[b.l];               //否则按照左结点分块排
    22 }
    23 void add(int x)
    24 {
    25     res+=flag[a[x]^K];
    26     flag[a[x]]++;
    27 }
    28 void del(int x)
    29 {
    30     flag[a[x]]--;
    31     res-=flag[a[x]^K];
    32 }
    33 int main()
    34 {
    35     scanf("%d%d%d", &N, &M, &K);
    36     int sz = sqrt(N);
    37     for(int i = 1;  i <= N; i++){  //读入数据
    38         scanf("%d", &a[i]);
    39         a[i] = a[i]^a[i-1];    //计算前缀异或和
    40         pos[i] = i/sz;         //分块
    41     }
    42     for(int i = 1; i <= M; i++){    //读入查询
    43         scanf("%d%d", &Q[i].l, &Q[i].r);
    44         Q[i].id = i;
    45     }
    46     sort(Q+1, Q+1+M, cmp);
    47     flag[0] = 1;
    48     for(int i = 1;  i <= M; i++){
    49         while(L < Q[i].l){    //当前左结点比查询结点小
    50             del(L-1);
    51             L++;
    52         }
    53         while(L > Q[i].l){    //当前左结点比查询左结点大
    54             L--;
    55             add(L-1);
    56         }
    57         while(R < Q[i].r){    //当前右结点比查询右结点小
    58             R++;
    59             add(R);
    60         }
    61         while(R > Q[i].r){    //当前右节点比查询右节点大
    62             del(R);
    63             R--;
    64         }
    65         ans[Q[i].id] = res;
    66     }
    67     for(int i = 1; i <= M; i++){
    68         printf("%lld
    ", ans[i]);
    69     }
    70 }
    View Code
  • 相关阅读:
    结巴分词 0.14 版发布,Python 中文分词库
    Lazarus 1.0.2 发布,Pascal 集成开发环境
    Android全屏 去除标题栏和状态栏
    服务器日志现 Android 4.2 传将添多项新特性
    Percona XtraBackup 2.0.3 发布
    长平狐 Android 强制设置横屏或竖屏 设置全屏
    NetBeans 7.3 Beta 发布,全新的 HTML5 支持
    CppDepend现在已经支持Linux
    GromJS 1.7.18 发布,服务器端的 JavaScript
    Apache OpenWebBeans 1.1.6 发布
  • 原文地址:https://www.cnblogs.com/ymzjj/p/9563453.html
Copyright © 2011-2022 走看看