「LOJ 10051」Nikitosh 和异或

给定一个含 $N$ 个元素的数组 $A$,下标从 $1$ 开始。请找出下面式子的最大值:
$$
(A[l1] xor A[l1 + 1] xor dots xor A[r1])
+(A[l2] xor A[l2 + 1] xor dots xor A[r2])
$$
其中 $1 leq l_1 leq r_1 < l_2 leq r_2 leq N$,$x xor y$ 表示按位异或。

链接

LOJ 10051

题解

利用按位异或的性质:$(x xor y) xor x = y$, 如果使用 $sum$ 记录异或前缀,即:
$$
sum[i] = A[1] xor A[2] xor dots xor A[i]
$$
那么:
$$
sum[l-1] xor sum[r] = A[l] xor A[l + 1] xor dots xor A[r]
$$
所以求 $l leq r$ 时最大的一段异或值,可以转化为求 $sum[0]$ 到 $sum[r]$ 中选出两个进行异或运算,求得到的结果最大是多少。与 LOJ 10050 解法相同,使用 Trie 树。

最后用 $l$ 和 $r$ 两个数组分别记录正序和倒序的最大值,循环一遍 $k (r_1 < k < l_2)$ 求最大值即可。

代码

#include <cstdio>
#include <cstring>

const int SIZE = 400005;
int ch[SIZE << 5][2], tot=1;
int num, a[SIZE], l[SIZE], r[SIZE];

int max(int a, int b) {
	return a > b ? a : b;
}

int insert(int num) {
	int u = 1;
	int _u = 1, res = 0;

	for (int i = 1 << 30; i; i >>= 1) {
		int c = (num & i) ? 1 : 0;
		int _c = !c;
		if (!ch[u][c]) ch[u][c] = ++tot;
		u = ch[u][c];
		if (ch[_u][_c]) res += i, _u = ch[_u][_c];
		else _u = ch[_u][!_c];
	}
	return res;
}

void init() {
	num = 0, tot = 1;
	memset(ch, 0, sizeof(ch));
	insert(0); // l 可以等于 r,异或值为 0
}

int main() {
	int n, ans = 0;
	scanf("%d", &n);
	init();
	for (int i = 1; i <= n; i++) {
		scanf("%d", a + i);
		num ^= a[i];
		l[i] = max(l[i - 1], insert(num));
	}
	init();
	for (int i = n; i >= 1; i--) {
		num ^= a[i];
		r[i] = max(r[i - 1], insert(num));
	}
	for (int i = 1; i < n; i++) {
		ans = max(ans, l[i] + r[i + 1]);
	}
	printf("%d
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/lcfsih/p/14391317.html