问题陈述
给你一个长度为 NN 的整数序列 A=(A1,…,AN)A=(A1,…,AN) 。求以下表达式的值:
∑i=1N−1∑j=i+1N(Ai⊕Ai+1⊕…⊕Aj)i=1∑N−1j=i+1∑N(Ai⊕Ai+1⊕…⊕Aj) .
关于位向 XOR 的说明 非负整数 AA 和 BB 的位向 XOR 定义如下,表示为 A⊕BA⊕B :
- 在 A⊕BA⊕B 的二进制表示中,当且仅当 AA 和 BB 的二进制表示中 2k2k 位上的数字中恰好有一位是 11 时, 2k2k ( k≥0k≥0 )位上的数字是 11 ;否则,它是 00 。
例如, 3⊕5=63⊕5=6 }(二进制: 011⊕101=110011⊕101=110 )。
一般来说, kk 个整数 p1,…,pkp1,…,pk 的比特 XOR 定义为 (⋯((p1⊕p2)⊕p3)⊕⋯⊕pk)(⋯((p1⊕p2)⊕p3)⊕⋯⊕pk) 。可以证明这与 p1,…,pkp1,…,pk 的阶数无关。
限制因素
- 2≤N≤2×1052≤N≤2×105
- 1≤Ai≤1081≤Ai≤108
- 所有输入值均为整数。
#include <bits/stdc++.h>
using namespace std;
int n;
long long a[200010];
long long sum;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum+=a[i];
}
long long ans=0;
for(int i=0;i<=32;i++){
//cnt0和cnt1分别是 第一个数到某个数的异或和为0的个数,异或和为1的个数(即左端点个数)。
//x是第1个数到当前的异或和
long long cnt0=0,cnt1=0,x=0;
for(int j=0;j<=n;j++){//枚举右端点
//a[j]的第i位的二进制数
long long tmp=a[j]>>i&1;
//第1个数到当前的异或和
x^=tmp;
//cnt0个区间的异或和有2的i次方
if(x) ans+=(1<<i)*cnt0,cnt1++;
//cnt1个区间的异或和有2的i次方
else ans+=(1<<i)*cnt1,cnt0++;
}
}
cout<<ans-sum;//重复加了只含自己本身的区间
}