NC14247—Xorto—(位运算+前缀和)

https://ac.nowcoder.com/acm/problem/14247

题目描述

给定一个长度为 nnn 的整数数组,问有多少对互不重叠的非空区间,使得两个区间内的数的异或和为 000。

输入描述

第一行一个数 nnn 表示数组长度;
第二行 nnn 个整数表示数组; 1≤n≤10001\leq n\leq 10001n1000,0≤数组元素<1000000\leq 数组元素 \lt1000000<100000。

输出描述

一行一个整数表示答案。

示例1

输入

3
0 0 0

输出

5

说明

([1,1],[2,2]),([1,1],[3,3]),([1,1],[2,3]),([1,2],[3,3]),([2,2],[3,3])

思路:位运算,还是区间,考虑前缀和。

求不相互覆盖的两个区间异结果相同,假设[x,y]是右区间 异结果 是z,只要考虑左边区间有多少个异结果为z,一一对应即可。桶排序的思想,用一个计数数组计算左边区间的各个 异结果 有多少个。遍历数组中,以i为分割点,[l,i]和[i+1,r],暴力l和r,累计左边区间对右边区间的贡献。[l,i]的区间异结果为b[l-1]^b[i],相当于把[1,l-1]异两次,那就成0了。

import java.math.BigDecimal;
import java.math.BigInteger;
import java.awt.Checkbox;
import java.io.BufferedInputStream;
import java.util.*;
public class Main{
    
    public static void main(String []args) {
        Scanner scan=new Scanner(System.in);
        int[] a=new int[10005];
        int[] b=new int[10005];///异 前缀和
        long[] num=new long[1000086];///左边 异结果 计数
        long ans=0;
        int n=scan.nextInt();
        for(int i=1;i<=n;i++) {
            a[i]=scan.nextInt();
            b[i]=b[i-1]^a[i];
        }
        for(int i=1;i<=n;i++){//求左右区间的个数,因为不重叠,i包括在左边里,不包括在右边
            // 1 2 3 4 5
            for(int l=1;l<=i;l++) {
                int x=b[l-1]^b[i];
                num[x]++;
            }
            for(int r=i+1;r<=n;r++) {
                int x=b[i]^b[r];
                ans+=num[x];
            }
        }
        System.out.println(ans);
    }
}

 

posted @ 2020-04-16 13:29  守林鸟  阅读(162)  评论(0编辑  收藏  举报