子段异或(位运算)

 

链接:https://ac.nowcoder.com/acm/contest/3005/D
来源:牛客网

题目描述

输入一个数列a,你需要输出其中异或值为0的不同子段的数量。
一个子段 [l,r] ( 1≤l≤r≤n)的异或值为alal+1al+2ar,其中符号代表异或运算。
两个子段被视为相同的,当且仅当其开始和结束位置均对应相同。

输入描述:

第一行一个整数 n ,代表数列长度。
第二行 n 个整数,代表数列。

输出描述:

输出一个整数,代表答案。

输入

5
1 2 3 2 1

输出

2

说明

子段 [1,3] 和子段 [3,5] 是合法子段。

备注:

n≤200000,0≤ai≤230−1

 

[l,r]=a[l]a[l+1]...a[r1]a[r]

[1,l-1]=a[1]a[2]...a[l2]a[l1]

[1,r]=a[1]a[2]...a[r1]a[r]

所以有:[1,l1][1,r]=[l,r]

所以预处理出所有的前缀异或和即可,由于需要[l,r]=0,故[1,l-1]=[1,r]

如a[0]^...^a[i]的亦或前缀和与a[0]^...^a[i+k]的亦或前缀和相等,则a[i+1]^...^a[i+k]=0

配合map比较好

 

 1 #include 
 2 #include <string.h>
 3 #include 
 4 #include <string>
 5 #include 
 6 #include 
 7 #include 
 8 #include 
 9 #include 
10 #include <set>
11 #include 
12 #include 
13 const int INF=0x3f3f3f3f;
14 typedef long long LL;
15 const int mod=1e9+7;
16 const int maxn=2e5+10;
17 using namespace std;
18 
19 int sum[maxn];
20 map<int,int> mp;
21 
22 int main()
23 {
24     #ifdef DEBUG
25     freopen("sample.txt","r",stdin);
26     #endif
27     
28     int n;
29     scanf("%d",&n);
30     LL ans=0;//记得开long long 
31     mp[0]++;
32     for(int i=1;i<=n;i++)
33     {
34         int x;
35         scanf("%d",&x);
36         sum[i]=sum[i-1]^x;
37         if(mp.count(sum[i]))//如果该前缀和之前出现过 
38             ans+=mp[sum[i]];
39         mp[sum[i]]++;
40     }
41     printf("%lld\n",ans);
42     
43     return 0;
44 }

 

 

 

 

-

你可能感兴趣的:(子段异或(位运算))