子段異或
阿新 • • 發佈:2020-10-18
第一行一個整數 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; }