P9533

题目

符卡有一个长度为 n n n 的整数数组 a a a,符卡认为一个区间 [ l , r ] [l,r] [l,r] 是灵异区间当且仅当 ⨁ i = l r a i = 0 \bigoplus_{i=l}^ra_i=0 i=lrai=0,或者说这个区间内所有数字异或起来刚好等于 0 0 0

符卡有特殊的魔法,可以把任意一个灵异区间翻转。具体来说,如果 [ l , r ] [l,r] [l,r] 区间是灵异区间,那么符卡就可以对这个区间使用魔法,整个数组就会变成 a 1 , a 2 , … , a l − 1 , a r , a r − 1 , … , a l , a r + 1 , a r + 2 … , a n a_1,a_2,\dots,a_{l-1},a_r,a_{r-1},\dots,a_l,a_{r+1},a_{r+2}\dots,a_n a1,a2,,al1,ar,ar1,,al,ar+1,ar+2,an

现在符卡可以使用任意次数的魔法,符卡希望最后得到的数组的灵异区间数量能够尽可能多,你能告诉她最后最多有多少个灵异区间吗?

分析

这题的坑点:区间的反转对最终的结果没有影响。

证明:

  • 设两个灵异区间分别为 [ x 1 , y 1 ] , [ x 2 , y 2 ] [x_1, y_1],[x_2,y_2] [x1,y1],[x2,y2]
  • 如果他们不相交或包含则对结果没有影响。
  • 否则 x 1 < x 2 < y 1 < y 2 x_1 < x_2 < y_1 < y_2 x1<x2<y1<y2:可将 a a a 数组分割: [ x 1 , x 2 ] , [ x 2 + 1 , y 1 ] , [ y 1 + 1 , y 2 ] [x_1,x_2],[x_2 + 1,y_1],[y_1 + 1, y_2] [x1,x2],[x2+1,y1],[y1+1,y2]。若翻转第一个区间,则 ⨁ i = x 1 x 2 a i ⊕ ⨁ i = y 1 y 2 a i = 0 \bigoplus_{i=x_1}^{x_2}a_i \oplus \bigoplus_{i=y_1}^{y_2}a_i=0 i=x1x2aii=y1y2ai=0 [ x 1 , x 2 ] [x_1,x_2] [x1,x2] [ x 2 + 1 , y 1 ] [x_2 + 1,y_1] [x2+1,y1] 异或和也为 0 0 0,所以证明没有影响。

问题就转化成了求原序列里有多少个灵异区间,而相同的数按位异或肯定等于 0 0 0,所以我们可以用 map 存前缀异或和,每次将 m p [ a i ] mp[a_i] mp[ai] 计入答案,并将 1 ∼ i 1 \sim i 1i 的异或和加 1 1 1

代码

注意要开 long long,因为会有全是一种数的情况
#include 
#define int long long

using namespace std;

const int N = 1e5 + 5;
int n, a[N];

signed main(){
	cin >> n;
	for(int i = 1; i <= n; i ++){
		cin >> a[i];
	}
	map <int, int> mp;
	mp[0] = 1;//什么数都不选的异或和为0
	int sum = 0, ans = 0;
	for(int i = 1; i <= n; i ++){
		sum ^= a[i];
	 	ans += mp[sum];//累加答案
	 	mp[sum] ++;//将当前前缀异或和计入map
	}
	cout << ans;
}


你可能感兴趣的:(算法,c++,数据结构)