子段异或(位运算)
子段异或(位运算)
链接:https://ac.nowcoder.com/acm/contest/3005/D
来源:牛客网
题目描述
输入一个数列a,你需要输出其中异或值为0的不同子段的数量。
一个子段 [l,r] (1≤l≤r≤n)的异或值为al⊕al+1⊕al+2⊕…⊕ar,其中⊕符号代表异或运算。
两个子段被视为相同的,当且仅当其开始和结束位置均对应相同。
输入描述:
第一行一个整数 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[r−1]⊕a[r]
[1,l-1]=a[1]⊕a[2]⊕...⊕a[l−2]⊕a[l−1]
[1,r]=a[1]⊕a[2]⊕...⊕a[r−1]⊕a[r]
所以有:[1,l−1]⊕[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 <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <stack> 9 #include <queue> 10 #include <set> 11 #include <map> 12 #include <sstream> 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 }
-