「CodeChef REBXOR」Nikitosh and xor

Description

给定一个长度为 (n) 的数列 (a_1,a_2,...,a_n),选定四个整数 (l_1,r_1,l_2,r_2(1le l_1le r_1<l_2le r_2le n)),则函数 (operatorname{F}(l_1,r_1,l_2,r_2)) 的计算方式如下:

[operatorname{F}(l_1,r_1,l_2,r_2)=(a_{l_1}oplus a_{l_1+1} oplus cdots oplus a_{r_1})+(a_{l_2}oplus a_{l_2+1} oplus cdots oplus a_{r_2}) ]

对于所有符合条件的 ((l_1,r_1,l_2,r_2)) ,求 (operatorname{F}(l_1,r_1,l_2,r_2)) 的最大值。

Hint

(1le nle 4 imes 10^5, a_i in [0,10^9])

Solution

(operatorname{lmax}(i)) 为前 (i) 个数中选取连续的某一段,得到的最大异或和是多少。对于 (operatorname{rmax}(i)) 同样定义。

假设我们已经计算好了 (operatorname{lmax})(operatorname{rmax}) ,那么答案就是 (maxlimits_{i=1}^{n-1}{operatorname{lmax}(i)+operatorname{rmax}(i+1)})

选现在的问题就是如何求 (operatorname{lmax})(operatorname{rmax}) 了,以 (operatorname{lmax}) 为例:

(operatorname{pre}(i) = a_1oplus a_2oplus cdots oplus a_i)(其实就是前缀异或和)。

那么对于 (operatorname{pre}(i)) 我们需要找一个 (i) 之前的一个前缀异或和与之异或来得到一段异或和,并且要求这个异或得到的值尽可能大。

求最大异或和,很自然的想到 Trie 树:只要把 (operatorname{pre}(1,2,cdots ,i-1))(0) 存入 Trie 中,就可以找到这个最大异或值。

另外,这个最大异或值还不一定比上一个优,所以还需与 (operatorname{lmax}(i)) 取最大值。

综上: (operatorname{lmax}(i) = max(operatorname{lmax}(i-1), operatorname{query}(operatorname{pre}(i)))) ,其中 (operatorname{query}(x)) 是指在 Trie 中找到的与 (x) 的异或产生的最大值。

同理: (operatorname{rmax}(i) = max(operatorname{rmax}(i+1), operatorname{query}(operatorname{suf}(i)))) ,其中 (operatorname{suf}) 为后缀异或和。

时间复杂度 (O(nlog U))(U) 为值域。

注意事项:

  1. 第二次使用 Trie 前记得清空。
  2. 计算 (operatorname{suf},operatorname{rmax}) 时记得从 (n)(1)

Code

/*
 * Author : _Wallace_
 * Source : https://www.cnblogs.com/-Wallace-/
 * Problem : CodeChef REBXOR Nikitosh and  xor
 */
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 4e5 + 5;
const int S = N << 6;

int ch[S][2];
int total = 1;

void reset() {
	memset(ch, 0, sizeof ch);
	total = 1;
}
void insert(int val) {
	for (register int cur = 1, i = 30; ~i; --i) {
		int c = val >> i & 1;
		if (!ch[cur][c]) ch[cur][c] = ++total;
		cur = ch[cur][c];
	}
}
int search(int val) {
	int cur = 1, ret = 0;
	for (register int i = 30; ~i; --i) {
		int c = val >> i & 1;
		if (ch[cur][!c]) c ^= 1, ret |= 1 << i;
		cur = ch[cur][c];
	}
	return ret;
}

int ary[N], n;
int pre[N], suf[N];
int lmax[N], rmax[N];

signed main() {
	cin >> n;
	for (register int i = 1; i <= n; i++)
		cin >> ary[i];
	
	for (register int i = 1; i <= n; i++)
		pre[i] = pre[i - 1] ^ ary[i];
	for (register int i = n; i >= 1; i--)
		suf[i] = suf[i + 1] ^ ary[i];
	
	reset(), insert(0);
	for (register int i = 1; i <= n; i++)
		lmax[i] = max(lmax[i - 1], search(pre[i])), insert(pre[i]);
	reset(), insert(0);
	for (register int i = n; i >= 1; i--)
		rmax[i] = max(rmax[i + 1], search(suf[i])), insert(suf[i]);
	
	int ans = 0;
	for (register int i = 1; i < n; i++)
		ans = max(ans, lmax[i] + rmax[i + 1]);
	cout << ans << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/-Wallace-/p/12676519.html