前缀异或:XOR Segment (用的是前缀和的思想,所以暂且称这个方法为前缀异或)

XOR Segment

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 34   Accepted Submission(s) : 12
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

  给出 n 个数的数列,让你求出异或和为零的连续子段,如果有多个答案,要求连续字段长度最短,如果长度最短子段有多个,取最靠前的字段。
  异或操作体现在C++里面:^操作,两数做异或的含义是其对应的每一位二进制位做异或,例如:5 ^ 7 = (101) ^ (111) = (010) = 2

Input

第一行一个数据组数 T,(T <= 100)
每组数据第一行一个 n(n <= 10^6)
第二行给出 n 个数,0 <= 数值 < 10^5

Output

每组数据输出一行子段的左右端点,如果不存在这样的字段,输出-1

Sample Input

3
5
1 2 3 4 5
2
2 4
3
4 0 4

Sample Output

1 3
-1

2 2

解法思路:异或的性质是,两个相同的数异或为0,a^b^a = b; a^b^b = a; 根据这个性质,可以想到,连续异或一个序列,得到某个值,然后继续异或下去,如果再次得到这个

值,那么这两个值之间自然就有通过连续异或变为0的子序列。写法就像写前缀和一样,所以暂且称为前缀异或吧~

AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 1e6;
int a[maxn], b[maxn];
int record[maxn];
int main() {
	int T;
	cin >> T;
	while(T--) {
		int n;
		int left, right;
		scanf("%d", &n);
		int anslen = 1e6;
		memset(record, -1, sizeof(record));
		record[0] = 0; b[0] = 0; a[0] = 0;
		for(int i = 1; i <= n;i++) {
			cin >> a[i];
			b[i] = b[i-1]^a[i];
			if(record[b[i]] == -1) record[b[i]] = i;
			else {
				if(i-record[b[i]] < anslen) {
					left = record[b[i]]+1;
					right = i;
					anslen = i-record[b[i]];
				}
				record[b[i]] = i;
			}
		}
		if(anslen != 1e6) printf("%d %d\n", left, right);
		else printf("-1\n");
	}
	return 0;
} 




  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值