XOR and Favorite Number解题思路——莫队算法的应用

题目:luogu CF 617 E.

题目大意:给出一串数列a,以及一些询问[l,r]内的有多少的子段[i,j]使ai xor ai+1 xor...xor aj=k,k为固定常数.

题目好像是离线的,而且没有修改操作,所以这道题可以使用莫队.

我们可以考虑,如何用区间[l,r]的种数获得[l-1,r]的种数以及[l,r+1]的种数.

我们知道,异或的逆运算是异或,也就是说我们可以通过ai xor...xor aj和aj+1知道ai xor...xor aj+1,也可以用ai xor...xor aj+1和aj+1知道ai xor...xor aj.

具体细节看代码:

#include<bits/stdc++.h>
  using namespace std;
typedef long long LL;
const int N=100000;
struct seg{
  int l,r,in,id;
}e[N+1];
LL ans[N+1],cnt[N*20+1],now;
int l,r,a[N+1],n,m,k;
inline void into(){
  scanf("%d%d%d",&n,&m,&k);
  for (int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    a[i]^=a[i-1];
  }
  for (int i=1;i<=m;i++){
    scanf("%d%d",&e[i].l,&e[i].r);
    e[e[i].id=i].in=e[i].l+1>>9;      //以512个元素为一个块 
  }
}
bool cmp(seg a,seg b){
  return a.in<b.in||a.in==b.in&&a.r<b.r;
}
void get(int x,long long num){      //注意这里要开long long
  now+=num*cnt[a[x]^k];
  cnt[a[x]]+=num;
  if (num==-1&&k==0) ++now;
}
inline void work(){
  sort(e+1,e+1+m,cmp);
  r=l=1;++cnt[a[1]],++cnt[0];
  if (a[1]==k) now=1;
  else now=0;
  for (int i=1;i<=m;i++){
    while (l>e[i].l) --l,get(l-1,1);
    while (l<e[i].l) get(l-1,-1),l++;
    while (r>e[i].r) get(r--,-1);
    while (r<e[i].r) get(++r,1);
    ans[e[i].id]=now;
  }
}
inline void outo(){
  for (int i=1;i<=m;i++)
    printf("%lld\n",ans[i]);
}
int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80550098