子数组异或和

子数组异或和

给定一个长度为 n 的整数数组 a1,a2,,an

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

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

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

输入格式

第一行包含整数 n

第二行包含 n 个整数 a1,a2,,an

输出格式

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

数据范围

前三个测试点满足 2n10
所有测试点满足 2n3×1050ai<220

输入样例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

 

解题思路

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

  假设有异或和si=s1s2si,根据同一个数的异或和为0这个性质,那么有sij=s1s2sij=(s1si)(s1sj1)=sisj1

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

  因此可以枚举子区间的右端点i,找到左端点j+1,满足区间长度i(j+1)+1=ij为偶数,同时满足sisj=0,即si=sj。因此我们要在0i1中找到有多少个j满足sisj=0,同时ij为为偶数,即满足ij的奇偶性相同。因此可以开两个哈希表,分别统计j为奇偶时的sj

  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 @   onlyblues  阅读(117)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示