2020牛客寒假算法基础集训营4 D:子段异或
D : 子段异或
考察点 : 位运算,前缀和,异或的性质和应用
坑点 : 0 - L 的异或值是 0 的话也是一个区间
相同的值可能有多个,那么这时候区间就会有多个(x * (x + 1) / 2)
关于异或的性质和应用:https://www.cnblogs.com/prjruckyone/p/12302732.html
侃侃 :
怎么求区间异或值为 0 的区间呢 ?
在求这个之前,可以想一下怎么求区间 和 为 0 的区间呢?
我们知道一个区间和或者区间异或 [L,R] 都可以表示为 sum[R] - sum[L - 1];
(具体可参考上面那篇博客 : [关于异或的性质和应用](https://www.cnblogs.com/prjruckyone/p/12302732.html))
那么区间 和 怎么才会是 0 呢?是不是只有 相同的两个数相减才会 = 0,
同样的,我们知道 相同的两个值 异或 = 0;
那么我们只需要先求出所有的异或前缀和,然后看有多少值是相等的,然后根据相等的个数来计算区间即可。
Code:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 2e5 + 10;
int sum[maxn],a[maxn];
int n;
LL cnt = 0;
int main(void) {
scanf("%d",&n);
for(int i = 1; i <= n; i ++) {
scanf("%d",&a[i]);
if(i == 1) sum[i] = a[i];
else {
sum[i] = sum[i - 1] ^ a[i];
}
if(sum[i] == 0) cnt ++;
}
sort(sum + 1,sum + 1 + n);
LL ans = 0;
sum[n + 1] = -1;
for(int i = 1; i <= n; i ++) {
// if(sum[i] == 0) continue; // 0 相等的区间也要算上
if(sum[i] == sum[i + 1]) {
ans ++;
} else {
// if(ans != 1)
cnt += (ans * (ans + 1) / 2) ; // ans 至少是 1 对,
ans = 0;
}
}
cout << cnt << endl;
return 0;
}
如果说年轻人未来是一场盛宴的话,那么我首先要有赴宴的资格。