Description
【分析】(感谢nodgd同学)
所有的v[i]转化为二进制之后,我们发现无论怎么异或,不同位的答案是互不影响的
于是我们不妨一位一位的讨论:
假设所有a[i]的二进制第j位组成一个只含有0,1的序列b[i],那么b[i]的从l到r的区间的异或的值只与b[i]从l到r的"1"的个数有关。
假设b[i]的前缀和为sum[i]
·如果sum[i]是奇数,那么任意一个j<i的偶数sum[j]都可以使b[i]的区间从j+1到i是奇数个1;
·如果sum[i]是偶数,那么任意一个j<i的奇数sum[j]都可以使b[i]的区间从j+1到i是奇数个1;
于是我们只需要统计sum[i]有多少个奇数多少个偶数就能够求出,以i结尾的区间有多少个异或答案为1
由于这是二进制的某一位,所以在加答案的时候记得要左移多少位
【代码】
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=100005;
int N,v[MAXN];
void _in(int &x)
{
char t=getchar();
while(t<'0'||'9'<t) t=getchar();
for(x=0;'0'<=t&&t<='9';x=x*10+t-'0',t=getchar());
}
void _init()
{
_in(N);
for(int i=1;i<=N;i++)
_in(v[i]);
}
void _solve()
{
long long ans=0;
for(int j=0;j<=30;j++) //v[i]<=10^9,二进制不超过30位
{
long long s=(1<<j); //讨论二进制的第j位
long long c1=0,c2=1,sum=0;
//一开始前缀和为0。为了省空间没有开sum数组
//c1表示已经有多少个奇数的sum[i]
//c2表示已经有多少个偶数的sum[i],由于sum[0]=0是偶数,所以初值为1
for(int i=1;i<=N;i++) //直接扫一遍所有v[i]
{
if((v[i]&s)) sum++;
//如果a[i]这一位是"1" 那么sum[i]=sum[i-1]+1;否则不变
if(sum&1) //sum[i]是奇数的情况
{
c1++;
ans+=c2*s; //与前面c2个sum[i]偶数,可以异或成"1"
}
else //sum[i]是偶数的情况
{
c2++;
ans+=c1*s; //与前面c1个sum[i]奇数,可以异或成"1"
}
}
}
cout<<ans<<endl;
}
int main()
{
_init();
_solve();
return 0;
}