有任何问题可以在下面评论
题意:
长度为 n 的数组,问你有几种 a[l] ^ a[l+1] ^ …^ a[mid] = a[mid+1] ^ a[mid+2] ^ … ^ a[r]. mid=(l+r-1)/2 , mid必须是偶数,也就是等号两边都是偶数个。
思路:
小小分析一波:
两边的异或值相等…相等的两个数异或值难道不是0吗, 那不就是求 连续的序列 异或值相等有几个吗? tnnd…
那么问题就转换成了问这个总共的序列 有几个 连续的 异或值为0 的子序列。
那怎么搞呢?????? 其实和 另一种问题串联下,就大概就能想出来,
- ( 可以不看这个 ,直接看下面想出的方法)另一种问题: 对一个总序列 问有几个子序列 满足他们的 和 为0 , 前缀和 是吧~~ 判断前缀和相等的话,说明这段子序列的和为0. 同样这个方法也能用在这个问题上:
像前缀和 那样 统计 前缀异或(我临时想得这个名词,意会下 )出现的次数,出现2次 就有1个段,出现 3次 就有1+2 个段… ,题目中还有一个条件,就是mid必须是偶数,我们开个二维数组记录下他的奇偶性 就行。
~~~~ 另外 因为异或值可能很大,所以我用map来给异或值编号,这样n最大时3e5, 最多有 3e5 个异或值,开这样一个数组空间还是够的。
代码中 统计奇偶性 不理解的话看这里:
假如 x[l]…x[r] 这段区间异或和为0,那么前缀异或和 now,异或到x[r]的时候,now == x[l-1],l,r是一个奇数一个偶数,l-1和r 的奇偶性肯定相同
代码:
#include<bits/stdc++.h>
#include<map>
#define ll long long
using namespace std;
const int maxn=3e6+177;
int l[maxn][5];
map<int,int >ma;
int main(){
int n;
cin>>n;
int x;
int now=0;
ll ans=0;
memset(l,0,sizeof(l));
l[1][0]=1;
ma[0]=1;
int cnt=2;
for(int i=1;i<=n;i++){
cin>>x;
now=now^x;
if(!ma[now]){
ma[now]=cnt++;
}
// cout<<now<<" $ "<<i<<endl;
ans=ans+l[ma[now]][i&1];
l[ma[now]][i&1]++; //出现次数加1
}
cout<<ans<<endl;
}