题目
符卡有一个长度为 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,…,al−1,ar,ar−1,…,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=x1⨁x2ai⊕i=y1⨁y2ai=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
1∼i 的异或和加
1
1
1。
代码
注意要开 long long
,因为会有全是一种数的情况
#include <bits/stdc++.h>
#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;
}