1. 程式人生 > 實用技巧 >子段異或

子段異或

傳送門

第一行一個整數 n ,代表數列長度。 第二行 n 個整數,代表數列。

輸出描述:

輸出一個整數,代表答案。
示例1

輸入

複製
5
1 2 3 2 1

輸出

複製
2

說明

子段 [1,3] 和子段 [3,5] 是合法子段。
意思就是給你一個子串,問有多少個子串異或和為0

解析:就是先知道一個知識就是如果x^y==0,則x==y。
設b[i]為異或字首和,則
b[i] = a[1] ^ a[2] ^ ... ^ a[i - 1] ^ a[i]
那麼對於一段[1,r]來說,異或字首和為b[r],那麼如果想要以r結尾的異或為0的子段的右半部分,
那麼只需要前面出現過一個數b[i] == b[r],那麼[i + 1,r]這一段異或和為0
就是:
如果在r的前面出現一個i,使得b[i]==b[r]則i+1到r的異或和為0



#include<map>
#include<string> 
#include <math.h> 
#include<memory.h>
#include<cstring>
#include<iostream>
#include<algorithm> 
using namespace std; 
typedef long long ll; 
int read() {
    int x = 0, f = 1; char s;
    
while((s = getchar()) > '9' || s < '0') {if(s == '-') f = -1;} while(s <= '9' && s >= '0') { x = (x << 1) + (x << 3) + (s ^ 48); s = getchar(); } return x * f; } const int INF=0x3f3f3f3f; const int maxn=1e6+122; //子段異或和為0 //設b[r]為他的異或字首和 //有b[r]==b[1]^b[2]......^b[r]
//如果在前面出現一個b[i]==b[r]則i+1到r的異或和為0 map<int,int>mp; ll a[maxn]; ll b[maxn]; int main(){ int n; cin>>n; ll ans=0; for(int i=1;i<=n;i++){ cin>>a[i]; b[i]=b[i-1]^a[i]; if(b[i]==0){ ans++; } ans+=mp[b[i]]; mp[b[i]]++; } cout<<ans<<endl; }