NC14247—Xorto—(位运算+前缀和)
https://ac.nowcoder.com/acm/problem/14247
题目描述
给定一个长度为 nnn 的整数数组,问有多少对互不重叠的非空区间,使得两个区间内的数的异或和为 000。
输入描述
第一行一个数 nnn 表示数组长度;
第二行 nnn 个整数表示数组; 1≤n≤10001\leq n\leq 10001≤n≤1000,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); } }