upc 6759 异或序列(莫队)

题目描述

已知一个长度为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

题解:纯…莫队模板
莫队用于解决离线算法,能优化区间时间复杂度

异或:a^a=0;a^0=a;
     若a^b=k;则a^k=b;b^a=k;b^k=a;
     所以根据异或的特性,我们用前缀和维护
     莫队算法一般模板大体不变,变得仅仅是add(int)和remove(int)

莫队模板:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int p[N],flag[N];//flag记录前缀出现的次数
int a[N];
int n,m,k,s=0;
long long ans[N];
int l=1,r=0;
struct node{

int l,r,id;
}q[N];
int cmp(node a,node b){

if(p[a.l]==p[b.l])//p记录的是
    return a.r<b.r;
return p[a.l]<p[b.l];

}

void add(int x){  //x位置的数字加入进来
 // printf("111%d\n",x);
    s+=flag[a[x]^k];
    flag[a[x]]++;
    //cnt[x]++;
    //if (cnt[x]==k) ans++;
}
void remove1(int x){  //x位置的数字移出去
   //  printf("222%d\n",x);
     flag[a[x]]--;
      s-=flag[a[x]^k];
    //cnt[x]--;
    //if (cnt[x]==k-1) ans--;
}

int main(){
scanf("%d%d%d",&n,&m,&k);
int block=sqrt(n);
a[0]=0;
for(int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    a[i]=a[i]^a[i-1];
    p[i]=i/block;//分块
}
for(int i=1;i<=m;i++){
    //scanf("%d%d",&q[i].l,&q[i],r);
    cin>>q[i].l>>q[i].r;
   // printf("check%d,%d\n",q[i].l,q[i].r);
    q[i].id=i;
}
sort(q+1,q+1+m,cmp);
flag[0]=1;
//int r=0;
for(int i=1;i<=m;i++){
while(l<q[i].l){
    remove1(l-1);
    l++;
    //printf("lll");
}
while(l>q[i].l){
    l--;
    add(l-1);
     //printf("lll");
}
 while(r<q[i].r){
    r++;
    add(r);
     //printf("rrr");
}
while(r>q[i].r){
    remove1(r);
    r--;
     //printf("rrr");
}
//printf("hhh%d,%d\n",q[i].id,s);
ans[q[i].id]=s;
}
for(int i=1;i<=m;i++){
printf("%lld\n",ans[i]);

}

return 0;
}

猜你喜欢

转载自blog.csdn.net/eternityZZing/article/details/81542960
UPC