2020牛客寒假算法基础集训营4 D:子段异或

D : 子段异或


考察点 : 位运算,前缀和,异或的性质和应用
坑点 : 0 - L 的异或值是 0 的话也是一个区间
相同的值可能有多个,那么这时候区间就会有多个(x * (x + 1) / 2)

关于异或的性质和应用:https://www.cnblogs.com/prjruckyone/p/12302732.html

侃侃 :

怎么求区间异或值为 0 的区间呢 ? 
在求这个之前,可以想一下怎么求区间 和 为 0 的区间呢?
我们知道一个区间和或者区间异或 [L,R] 都可以表示为 sum[R] - sum[L - 1];
(具体可参考上面那篇博客 : [关于异或的性质和应用](https://www.cnblogs.com/prjruckyone/p/12302732.html))
那么区间 和 怎么才会是 0 呢?是不是只有  相同的两个数相减才会 = 0,
同样的,我们知道 相同的两个值 异或 = 0;
那么我们只需要先求出所有的异或前缀和,然后看有多少值是相等的,然后根据相等的个数来计算区间即可。

Code:


#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;
const int maxn = 2e5 + 10;
int sum[maxn],a[maxn];
int n;

LL cnt = 0;

int main(void) {
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++) {
        scanf("%d",&a[i]);
        if(i == 1) sum[i] = a[i];
        else {
            sum[i] = sum[i - 1] ^ a[i];
        }
        if(sum[i] == 0) cnt ++;
    }
    sort(sum + 1,sum + 1 + n);
    LL ans = 0;
    sum[n + 1] = -1;
    for(int i = 1; i <= n; i ++) {
//      if(sum[i] == 0) continue;          // 0 相等的区间也要算上
        if(sum[i] == sum[i + 1]) {
            ans ++;
        } else {
//          if(ans != 1)
            cnt += (ans * (ans + 1) / 2) ;  // ans 至少是 1 对,
            ans = 0;
        }
    }
    cout << cnt << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/prjruckyone/p/12302842.html