子段异或(异或前缀和)

传送门

第一行一个整数 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;
}
复制代码

 

 

 

 



posted @   lipu123  阅读(1283)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示