题目:
异或和之和
题目描述
给定一个数组 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≤1e5,0≤Ai≤2的20次方。
思路:
如果暴力求,就需要三层循环,超时的,所以我们可以利用前缀和数组。为什么异或也可以呢,
pre[j] 是 arr[1] ^ arr[2] ^ ... ^ arr[j]
pre[i-1] 是 arr[1] ^ arr[2] ^ ... ^ arr[i-1]
当我们计算 pre[j] ^ pre[i-1] 时,从arr[1]到arr[i-1]的部分在两个前缀和中都存在,并且由于异或的自反性(a ^ a = 0),这些部分会被抵消掉,留下的就是arr[i]到arr[j]的异或结果。
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1e5+5;
ll n;
ll arr[N];
ll pre[N];
ll sum;
int main()
{
cin >> n;
for(ll i = 1 ; i <= n ; i++)
{
cin >> arr[i];
pre[i] = pre[i-1] ^ arr[i];
}
for(ll i = 1 ; i <= n ; i++)
{
for(ll j = i ; j <= i ; j++)
{
sum += (pre[j] ^ pre[i-1]);
}
}
cout << sum;
return 0;
}
O(n*n)肯定超时啊