P4462-题解
_zuoqingyuan · · 题解
题意简述
传送门。
给定一个长度为
数据范围:
思路分析
前置知识:莫队。
在此之前,我们要先知道异或运算是个什么东西:就是将两个二进制数的最低位对其,依次比较两个二进制数的每一位,如果相同,则得到的结果为
从定义可以推导出来的结论:对于任意
我们定义
根据异或的定义,我们可以很方便的推出:如果
结论部分讲解完毕,让我们回到题面,注意到是区间静态问题,不要求强制在线,显然可以用莫队乱搞。
我们在上文提到
如果有
已知
坑点大全:
-
因为询问是区间
[L,R] ,而处理时会将L-1 。所以会出现左边界为0 的情况。因此莫队中两个指针的初始位置都是0 . -
初始情况下,区间包含
s_0=0 ,所以cnt_0 初值为1 。 -
当
k=0 时,对于任何a 都有a\oplus 0=a 。因此在删除时,应当先对cnt 操作,再对答案ans 操作(我 WA 了好几次)。 -
虽然
a_i 小于10^5 ,但如果a_1=100000,a_2=31071 ,s_2 有最大值为377777 。所以cnt 的大小一定要把控好(好像数据不卡这个)。
莫队是什么大家应该也知道吧,毕竟我都讲完了。
Code
码风不好,勿抄。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=4e5+10;
typedef long long ll;
ll n,m,k,a[N],t,cnt[N],ans,ql,qr,l,r,res[N];
struct node{
ll l,r,idx;
}b[N];
inline void read(ll &x){
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return;
}
inline void write(ll x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
bool cmp(node a,node b){
return (a.l/t)^(b.l/t)?a.l<b.l:((a.l/t)&1?a.r<b.r:a.r>b.r);//常数优化
}
inline void add(int x){
ans+=cnt[a[x]^k];
cnt[a[x]]++;
}
inline void del(int x){
cnt[a[x]]--;//如果你100pts,但 Unaccepted,你很可能错这里了。一定要先修改cnt再修改ans.具体可以看我上面说的坑点(第3条)。
ans-=cnt[a[x]^k];
}
int main(){
read(n),read(m),read(k);t=sqrt(n);
for(int i=1;i<=n;i++)read(a[i]),a[i]^=a[i-1];
for(int i=1;i<=m;i++)read(b[i].l),read(b[i].r),b[i].l--,b[i].idx=i;
sort(b+1,b+1+m,cmp);
cnt[0]=1;
for(int i=1;i<=m;i++){
ql=b[i].l,qr=b[i].r;
while(l<ql)del(l++);
while(l>ql)add(--l);
while(r<qr)add(++r);
while(r>qr)del(r--);
res[b[i].idx]=ans;
}
for(int i=l;i<=m;i++){
write(res[i]);putchar('\n');
}
return 0;
}
AC 记录。
如有错误,请指出。