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;
}

posted @ 2020-02-13 11:29  IceSwords  阅读(137)  评论(0编辑  收藏  举报