子数组异或和

子数组异或和

给定一个长度为 $n$ 的整数数组 $a_1,a_2, \dots ,a_n$。

请你统计一共有多少个数组 $a$ 的非空连续子数组能够同时满足以下所有条件:

  • 该连续子数组的长度为偶数。
  • 该连续子数组的前一半元素的异或和等于其后一半元素的异或和。

例如,当给定数组为 $[1,2,3,4,5]$ 时,满足条件的连续子数组只有 $1$ 个:$[2,3,4,5]$。

输入格式

第一行包含整数 $n$。

第二行包含 $n$ 个整数 $a_1,a_2, \dots ,a_n$。

输出格式

一个整数,表示满足条件的连续子数组的数量。

数据范围

前三个测试点满足 $2 \leq n \leq 10$。
所有测试点满足 $2 \leq n \leq 3 \times {10}^{5},0 \leq a_i < 2^{20}$。

输入样例1:

5
1 2 3 4 5

输出样例1:

1

输入样例2:

6
3 2 2 3 7 6

输出样例2:

3

输入样例3:

3
42 4 2

输出样例3:

0

 

解题思路

  这题昨天想了很久都没想出来怎么做,想到了用异或前缀和,但没发现题目第二个隐含的性质,现在做题的抽象能力十分差,很难把一个问题抽象成学过的模型。

  假设有异或和$s_i = s_1 \wedge s_2  \wedge \dots \wedge s_i$,根据同一个数的异或和为$0$这个性质,那么有$$\begin{align*} s_{i - j} &= s_1 \wedge s_2 \wedge \dots \wedge s_{i - j} \\ &= (s_1 \wedge \dots \wedge s_i) \wedge (s_1 \wedge \dots \wedge s_{j-1}) \\ &= s_i \wedge s_{j - 1} \end{align*}$$

  对于第二个条件,假设子数组前一半的异或和为$x$,后一半的异或和为$y$,那么就有$x \wedge y = 0$,因此有$x = y$。

  因此可以枚举子区间的右端点$i$,找到左端点$j+1$,满足区间长度$i - (j + 1) + 1 = i - j$为偶数,同时满足$s_i \wedge s_{j} = 0$,即$s_i = s_{j}$。因此我们要在$0 \sim i - 1$中找到有多少个$j$满足$s_i \wedge s_{j} = 0$,同时$i-j$为为偶数,即满足$i$和$j$的奇偶性相同。因此可以开两个哈希表,分别统计$j$为奇偶时的$s_j$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1 << 20;
 5 
 6 int cnt[2][N];  // 因为ai<2^20,因此异或和不超过2^20
 7 
 8 int main() {
 9     int n;
10     scanf("%d", &n);
11     
12     long long ret = 0;
13     cnt[0][0] = 1;
14     for (int i = 1, sum = 0; i <= n; i++) {
15         int v;
16         scanf("%d", &v);
17         sum ^= v;
18         ret += cnt[i & 1][sum];
19         cnt[i & 1][sum]++;
20     }
21     
22     printf("%lld", ret);
23     
24     return 0;
25 }

 

参考资料

  AcWing 4507. 子数组异或和(AcWing杯 - 周赛):https://www.acwing.com/video/4213/

posted @ 2022-08-14 21:21  onlyblues  阅读(90)  评论(0编辑  收藏  举报
Web Analytics