zoukankan      html  css  js  c++  java
  • 6759: 异或序列

    6759: 异或序列

    时间限制: 1 Sec  内存限制: 128 MB

    题目描述

    已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在al,al+1,…,ar区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足ax⊕ax+1⊕⋯⊕ay=k的x,y有多少组。

    输入

    输入第一行为3个整数n,m,k。第二行为空格分开的n个整数,即a1,a2,…,an。接下来m行,每行两个整数lj,rj,代表一次查询。

    输出

    输出共m行,对应每个查询的计算结果。

    样例输入

    4 5 1
    1 2 3 1
    1 4
    1 3
    2 3
    2 4
    4 4
    

    样例输出

    4
    2
    1
    2
    1
    

    提示

    对于30%的数据,1≤n,m≤1000。
    对于100%的数据,1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n。

    来源/分类

    重庆OI2018 

    看到多次区间查询,就想到了莫队算法,但是莫队中对于区间状态转移的处理却是需要斟酌。

    题目已经很明显的提示了,异或异或,也许我们应该使用异或前缀和,(orz)

    对于异或前缀和 我们知道 i and j 之间的异或和 == sum[j]^sum[i-1] 

    那么对于l 如果小于 Q.l-1,那么我们就先清除这位置的影响,然后下标++

    如果大于Q.l-1,那就下标--,再加上这位置影响

    我们要让求异或为k的组合数

    sum[j] ^ sum[i] = k 即 sum[j] ^ k = sum[i]

    用cnt 记录 区间内前缀和的数量变化

    那么ans += val * (cnt[sum[j] ^ k])即这个点所造成的k组数影响

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<math.h>
     4 #include<algorithm>
     5 using namespace std;
     6  
     7 const int maxn = 1e5+5;
     8 int n,m,k;
     9 int block;
    10 int sum[maxn];
    11 int ans;
    12 int tmp;
    13 int cnt[maxn];
    14  
    15 struct node
    16 {
    17     int l,r,id,ans;
    18     friend bool operator < (const node &a,const node&b)
    19     {
    20         if(a.l / block != b.l / block)return a.l < b.l;
    21         return a.r < b.r;
    22     }
    23     node(){}
    24     node(int l,int r,int id):l(l),r(r),id(id){}
    25 }Q[maxn];
    26  
    27 bool cmp(node a,node b)
    28 {
    29     return a.id < b.id;
    30 }
    31  
    32 void revise(int x,int val)
    33 {
    34     cnt[sum[x]]+=val;
    35     ans += val*cnt[sum[x]^k];
    36 }
    37 int main()
    38 {
    39     scanf("%d%d%d",&n,&m,&k);
    40     block = sqrt(n);
    41     for(int i=1;i<=n;i++)
    42     {
    43         scanf("%d",&tmp);
    44         sum[i] = tmp ^ sum[i-1];
    45     }
    46     for(int i=1;i<=m;i++)
    47     {
    48         scanf("%d%d",&Q[i].l,&Q[i].r);
    49         Q[i].id = i;
    50     }
    51     sort(Q+1,Q+m+1);
    52     int l = 1,r = 0;
    53     ans = 0;
    54     for(int i=1;i<=m;i++)
    55     {
    56         while(l < Q[i].l - 1)revise(l,-1),l++;
    57         while(l > Q[i].l - 1) l--,revise(l,1);
    58         while(r < Q[i].r)r++,revise(r,1);
    59         while(r > Q[i].r)revise(r,-1),r--;
    60         Q[i].ans = ans;
    61     }
    62     sort(Q+1,Q+m+1,cmp);
    63     for(int i=1;i<=m;i++)printf("%d
    ",Q[i].ans);
    64     return 0;
    65 }
    View Code
  • 相关阅读:
    每周必写
    每周必写
    每周必写
    中国历史上成功的两人合作, 改进, 提高的例子
    每周必写(3)
    结对编程进度及自己的理解
    每周必写
    IT行业的“创新”、“模仿”
    工作时间内容,感想和思考
    周阅读内容
  • 原文地址:https://www.cnblogs.com/iwannabe/p/9539460.html
Copyright © 2011-2022 走看看