题目链接
思路:首先区间异或有一个性质s【l-1】^s【r】=s【l。。。。r】,所以我们考虑异或前缀和,我们从k的每位二进制来考虑,在已经构造好的字典树中,如果k的第pos位是0,那么我们看看当前字典树能不能走相反的方向,能的话就能把这一位异或为1,就会对他们产生贡献,加上经过这条边的个数就行了,如果第pos位是1的话我们最低要求也得保障我们字典树这一位异或起来是1才行,不然如果是0的话就不可能会比k大了,然后逐步更新字典树就行,不过这里的k要减1才行,不然会漏掉与k相等的情况。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5;
ll cnt=0,k,tree[maxn*20][2],sum[maxn*20],a[maxn],ans;
void insert(ll x)
{
int u=0;
for(int i=31;i>=0;--i)
{
int t=(((1LL<<i)&x)?1:0);
if(!tree[u][t]) tree[u][t]=++cnt;
sum[tree[u][t]]++;
u=tree[u][t];
}
}
void query(ll x)
{
int u=0;
for(int i=31;i>=0;--i)
{
int t=(((1LL<<i)&x)?1:0),s=(((1LL<<i)&k)?1:0);
if(s==0) {
if(tree[u][t^1]) ans+=sum[tree[u][t^1]];
u=tree[u][t];
}
else {
if(tree[u][t^1]) u=tree[u][t^1];
else u=0;
}
if(!u) break;
}
}
int main()
{
int n;
scanf("%d%lld",&n,&k);
k--;
insert(0);
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
a[i]^=a[i-1];
query(a[i]);
insert(a[i]);
}
printf("%lld\n",ans);
}