子段異或(異或前綴和)


傳送門

第一行一個整數 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