2020牛客寒假算法基础集训营4 D 子段异或

https://ac.nowcoder.com/acm/contest/3005/D
题目描述

输入一个数列a,你需要输出其中异或值为0的不同子段的数量。一个子段[l,r](1\leqslant l\leqslant r\leqslant n)的异或和a_{l}\oplus a_{l+1}\oplus \cdot \cdot \cdot \oplus a_{r}其中\oplus符号表示异或。两个子段被视为相同的,当且仅当其开始和结束位置均对应相同。

思路

考虑它的前缀和,如果区间[1,r]异或和为0,那么它和前面所有所有的异或和为0的连续的区间异或依然为0,如果前缀和[1,r]=a,前缀和[1,rr]=a,说明rrr中有一段为0,所以只需要从头计算前缀和,并且把每一个前缀和出现的次数记录下来,在计算当前位置的前缀和的时候,如果前面有k个和这个位置相同的前缀和,说明他可以和前面k个不同连续区间组成为0的子段。

#include <bits/stdc++.h>
#pragma warning (disable:6031)
#pragma warning (disable:4996)
#define mem(a, b) memset(a, b, sizeof a);
using namespace std;
const int N = 200100;
typedef long long ll;
int n;
int a[N];
ll f[N];
int main()
{
	scanf("%d", &n);
	ll res = 0;
	for (int i = 1; i <= n; i++) {
		scanf("%d", a + i);
	}
	ll temp = 0;
	map<ll, ll> s;
	s.clear();
	for (int i = 1; i <= n; i++) {
		temp ^= a[i];
		if (temp == 0)++res;
		if (s[temp]) {
			res += s[temp];
		}
		s[temp]++;
	}
	printf("%lld\n", res);
	return 0;
}

 

posted @ 2020-02-11 19:08  correct  阅读(72)  评论(0)    收藏  举报