预处理前缀异或和, 再按位拆分。
则求区间 $[i, j]$ 的异或和为 $s_j$ ^ $s_{i - 1}$
枚举所有区间的右端点,若右端点的第 $j$ 位是 $1$, 则该数会与前面每个第 $j$ 位是 $0$ 的左端点 异或后 第 $j$ 位仍然是 $1$, 就会产生 $2^j$ 的贡献。
反之 右端点的第 $j$ 位是 $0$ 同理
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long i64;
const int N = 1e5 + 10;
int n;
int s[N];
int cnt[30][2];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &s[i]);
for (int i = 1; i <= n; i ++ ) s[i] ^= s[i - 1];
for (int i = 0; i < 30; i ++ ) cnt[i][0] = 1;
i64 ans = 0;
for (int i = 1; i <= n; i ++ ) {
for (int j = 0; j < 30; j ++ ) {
int v = s[i] >> j & 1;
ans += cnt[j][v ^ 1] * (1ll << j);
cnt[j][v] ++ ;
}
}
printf("%lld\n", ans);
return 0;
}
牛