子段异或(异或前缀和)


传送门

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

输出描述:

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

输入

复制
5
1 2 3 2 1

输出

复制
2

说明

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


首先你得知道一个知识点就是:如果sum[i]为数组a的前i项的异或和,就是说sum[i]=a[1]^a[2]^a[3]^----a[i]

那么就有l<=r<=i,sum[l]^sum[l+1]^sum[l+2]^sum[l+3]------^sum[r]=sum[r]^sum[l-1]

 

意思就是给你一个子串,问有多少个子串异或和为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+1r的异或和为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;
} 
 

 


例二:
传送门

 

 

 

Examples
input
Copy
5
1 2 3 4 5
output
Copy
1
input
Copy
6
3 2 2 3 7 6
output
Copy
3
input
Copy
3
42 4 2
output
Copy
0
Note

Be as cool as Sasha, upsolve problems!

In the first example, the only funny pair is (2,5)(2,5), as 23=45=12⊕3=4⊕5=1.

In the second example, funny pairs are (2,3)(2,3), (1,4)(1,4), and (3,6)(3,6).

In the third example, there are no funny pairs.

 题目大意:

给你一个数列 求有多少区间满足

1 长度为偶数

2 前一半异或值等于后一半异或值

思路

前一半异或值等于后一半异或值 那么这个区间异或值为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=5e6+100;
ll a[maxn];
ll b[maxn];
ll dp[maxn][2];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=b[i-1]^a[i];
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        if(b[i]==0&&i%2==0){
            ans++;
        }
        ans+=dp[b[i]][i%2];
        dp[b[i]][i%2]++;
    } 
    cout<<ans<<endl;
}

 

 

 

 




免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM