zoukankan      html  css  js  c++  java
  • [ CQOI 2018 ] 异或序列

    (\)

    Description


    给出一个长为 (n) 的数列 (A)(k),多次询问:

    对于一个区间 ([L_i,R_i]),问区间内有多少个不为空的子段异或和为 (k)

    • (n,m,k,A_ile 10^5)

    (\)

    Solution


    注意到一件有趣的事,就是每次询问的 (k) 相同。

    因为 (aoplus a=0),所以子段异或问题可以看作前缀异或和的异或,即

    [a[i]oplus a[i+1]oplus...oplus a[j]=sum[i-1]oplus sum[j] ]

    其中 (sum[i]=a[1]oplus a[2]oplus...oplus a[i])

    那么问题转化为,存在对少对 (i,jin[L_i-1,R_i],i!=j) ,满足

    [sum[i]oplus sum[j]=k ]

    注意区间问题,因为区间做差的原理是减掉 (l-1)

    然后可以注意到,一个值 (x) 若想要构成 (k) ,其对应的另一个值是固定的。

    也就是说,我们的组合方案是确定的。

    当新加入一个可选值 (x) ,我们的方案数就会 (+cnt[x^k]) ,其中 (cnt[i]) 表示当前含有可选值 (i) 的个数。

    可以证明,这种计数方式不会算重,因为每个数字加入时只会计算当前已经有对应的值。

    当去掉一个值的时候,方案数 (-cnt[x^k]) 即可。

    (\)

    还有一个问题,就是关于 (k=0) 的情况。

    此时每个值显然不能计算上自己和自己异或的贡献。

    删除时当然也要注意不能多减掉自己异或自己的情况。

    只需在 adddel 的时候交换一下操作顺序即可,具体看代码。

    (\)

    Code


    突然失智......Debug 2h 竟只是因为 (l) 没有减 (1) ......

    还要注意,刚开始 (0) 号位置也有一个贡献。

    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 100010
    #define R register
    #define gc getchar
    using namespace std;
    typedef long long ll;
    
    inline ll rd(){
      ll x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    ll n,m,k,ans,bl[N],cnt[1<<18],s[N],res[N];
    
    struct Q{ll l,r,id;}q[N];
    
    inline bool cmp1(Q x,Q y){
      return bl[x.l]==bl[y.l]?x.r<y.r:bl[x.l]<bl[y.l];
    }
    
    inline bool cmp2(Q x,Q y){return x.id<y.id;}
    
    inline void del(int p){
      --cnt[s[p]];
      ans-=cnt[k^s[p]];
    }
    
    inline void add(int p){
      ans+=cnt[k^s[p]];
      ++cnt[s[p]];
    }
    
    int main(){
      n=rd(); m=rd(); k=rd();
      ll t=sqrt(n);
      for(R ll i=1;i<=n;++i){
        s[i]=s[i-1]^rd();
        bl[i]=i/t+1;
      }
      for(R ll i=1;i<=m;++i){
        q[i].l=rd()-1; q[i].r=rd(); q[i].id=i;
      }
      sort(q+1,q+1+m,cmp1);
      ll nowl=0,nowr=0;
      cnt[0]=1;
      for(R ll i=1;i<=m;++i){
        while(nowl>q[i].l){--nowl;add(nowl);}
        while(nowl<q[i].l){del(nowl);++nowl;}
        while(nowr<q[i].r){++nowr;add(nowr);}
        while(nowr>q[i].r){del(nowr);--nowr;}
        res[q[i].id]=ans;
      }
      for(R ll i=1;i<=m;++i) printf("%lld
    ",res[i]);
      return 0;
    }
    
    
  • 相关阅读:
    什么是内存泄漏?
    将博客搬至CSDN
    jQuery基础事件处理
    vue的特殊指令 v-if v-once v-bind v-for v-on v-model
    svg 直线水平渐变为什么没有效果,必须得是一条倾斜的不水平的直线才有渐变效果呢??
    jQuery基础
    Html 对象的常用事件列举
    javascript应该嵌入到html中的什么位置
    javascript document.createElement() document.createTextNode() appendChild()
    html canvas
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9994231.html
Copyright © 2011-2022 走看看