题目:
题意:
给出一个序列,问有多少种 [ l , r ] [l,r] [l,r]能满足 a l x o r a l + 1 … a r − 1 x o r a r > = k a_l\ xor\ a_{l+1}\ …a_{r-1}\ xor\ a_r>=k al xor al+1 …ar−1 xor ar>=k
分析:
我们将所有二进制放到树上,对于
=
k
=k
=k时,也就是从根走到相同的长度时所有数字都一样
那对于
>
k
>k
>k的情况,我们想下,
k
=
10100
k=10100
k=10100时,当序列是
1
∗
∗
∗
∗
∗
1*****
1∗∗∗∗∗或
01
∗
∗
∗
01***
01∗∗∗时就一定能保证
>
k
>k
>k了
所以我们可以从高到低遍历,这样就可以保证前缀相同,然后当
k
k
k的下一位是
0
0
0,我们就可以选择
1
1
1了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define LL long long
using namespace std;
inline LL read()
{
int s=0,f=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {s=s*10+c-'0';c=getchar();}
return s*f;
}
LL lim=30,n,m;
struct Trie{
LL size[30000005],c[30000005][2],tot;
void clean(LL k)
{
if(c[k][0]) clean(c[k][0]);
if(c[k][1]) clean(c[k][1]);
size[k]=c[k][0]=c[k][1]=0;
return;
}
void ins(LL x)
{
LL k=1;
for(LL i=lim;i>=0;i--)
{
LL t=(x>>i)&1;
if(!c[k][t]) c[k][t]=++tot;
k=c[k][t];
size[k]++;
}
return;
}
LL query(LL x)
{
LL k=1,sum=0;
for(LL i=lim;i>=0;i--)
{
LL t1=(x>>i)&1,t2=(m>>i)&1;
if(!t2) sum+=size[c[k][t1^1]];
k=c[k][t1^t2];
}
return sum+size[k];
}
}trie;
int main()
{
// freopen("xor.in","r",stdin);
// freopen("xor.out","w",stdout);
LL t=read();
while(t--)
{
n=read(),m=read();
trie.tot=1;
trie.clean(1);
trie.ins(0);
LL x=0,ans=0;
for(LL i=1;i<=n;i++)
{
x^=read();
ans+=trie.query(x);
trie.ins(x);
}
printf("%lld\n",ans);
}
return 0;
}