【题目来源】
https://www.luogu.com.cn/problem/P9236
【题目描述】
给定一个数组 Ai,分别求其每个子段的异或和,并求出它们的和。或者说,对于每组满足 1≤L≤R≤n 的 L,R,求出数组中第 L 至第 R 个元素的异或和。然后输出每组 L,R 得到的结果加起来的值。
【输入格式】
输入的第一行包含一个整数 n 。
第二行包含 n 个整数 Ai,相邻整数之间使用一个空格分隔。
【输出格式】
输出一行包含一个整数表示答案。
【输入样例】
5
1 2 3 4 5
【输出样例】
39
【数据范围】
对于 30% 的评测用例,n≤300;
对于 60% 的评测用例,n≤5000;
对于所有评测用例,1≤n≤10^5,0≤Ai≤2^20。
【算法分析】
● 异或运算的基本性质
异或运算(XOR)具有以下重要性质:
交换律:a ^ b = b ^ a
结合律:a ^ (b ^ c) = (a ^ b) ^ c
自反性:a ^ a = 0
零元素:a ^ 0 = a
可逆性:如果 a ^ b = c,那么 a = c ^ b
● 前缀异或和重要性质
求证:若定义前缀异或和 s[i]=a[0]^a[1]^a[2]^…^a[i],则子区间 [le,ri] 的异或和等于 s[ri]^s[le−1]。
证明:由前缀异或和的定义,知:
s[ri] = a[0]^a[1]^a[2]^…^a[ri],s[le−1] = a[0]^a[1]^a[2]^…^a[le−1]。
所以 s[ri]^s[le−1] = (a[0]^a[1]^…^a[ri]) ^ (a[0]^a[1]^…^a[le−1])
= (a[0]^a[1]^…^a[le−1]) ^ (a[0]^a[1]^…^a[le−1]^a[le]^…^a[ri])
= (a[0]^a[1]^…^a[le−1]) ^ (a[0]^a[1]^…^a[le−1]) ^ (a[le]^…^a[ri])
= 0 ^ (a[le]^…^a[ri])= a[le]^…^a[ri]
又已知区间 [le,ri] 的异或和等于 a[le]^…^a[ri]。
综上,得证。
【算法代码】
#include <bits/stdc++.h>
using namespace std;const int maxn=1e5+5;
int a[maxn],s[maxn];
int n;int main() {cin>>n;for(int i=1; i<=n; i++) {cin>>a[i];s[i]=s[i-1]^a[i];}long long ans=0;for(int i=1; i<=n; i++) { //prefix XOR sum of [i,j]for(int j=i; j<=n; j++) {ans+=(s[i-1]^s[j]);}}cout<<ans<<endl;return 0;
}/*
in:
5
1 2 3 4 5out:
39
*/
【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/154304346
https://www.luogu.com.cn/problem/solution/P9236
https://blog.csdn.net/lxr_lxr_/article/details/150269308