题意:给出一段序列,找出一个连续的前缀,一个连续的后缀,使这些数异或出来的值最大。除了前缀或后缀为空以外,前缀和后缀必须包含第一个和最后一个元素。
就是序列a1,a2,a3...an,找出前缀[0,l],后缀[r, n + 1],使这些数异或起来最大,其中r > l,a0和an+1假设它为0,就是说[0,0]表示前缀为空,[n+1,n+1]表示为后缀为空。
思路:这题有点神,没做过类似的题感觉有点难想出来,看了别人的解题报告之后发现,这题真的很神,忍不住把它写上了博客。首先可以将问题转化一下,可以发现序列的所有前缀和后缀都可以在O(n)的时间内求出来,然后问题就转化为了找出两个数异或起来最大,并且它们不能相交,异或起来最大就是尽量让这两个数的各个二进制位异或起来为1;接着字典树就派上用场了,首先我们枚举每一个后缀,在枚举的同时,将与其不相交的前缀插入到字典树中,并对于每一个后缀,我们可以求出和这个异或起来最大且不相交的前缀,至于求这个前缀,我们可以利用点贪心的思想,就是从高位开始枚举,就是越高位越能异或得到1就越好,这样我们就能求出这个前缀了。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
const int MAXBITS = 50;
LL num[N];
struct Node {
int key;
Node *child[2];
Node(){ child[0] = child[1] = NULL; key = 0; }
} *root;
struct Trie {
void insert(LL val) {
Node *s = root;
for(int i = MAXBITS; i >= 0; i--) {
int dir = ((1LL << i) & val) > 0;
if(s->child[dir] == NULL) {
Node *p = new Node;
p->key = dir;
s->child[dir] = p;
}
s = s->child[dir];
}
}
LL query(LL val) {
LL res = 0;
Node *s = root;
for(int i = MAXBITS; i >= 0; i--) {
int dir = ((1LL << i) & val) > 0;
if(s->child[!dir] != NULL)
s = s->child[!dir];
else
s = s->child[dir];
res += (1LL << i) * s->key;
}
return res;
}
} tree;
int main() {
int n, i;
cin >> n;
LL prefix = 0, suffix = 0, ans = 0;
for(i = 1; i <= n; i++) {
scanf("%I64d", &num[i]);
suffix ^= num[i];
}
for(i = 1; i <= n + 1; i++) {
tree.insert(prefix);
LL x = tree.query(suffix);
ans = max(ans, (x ^ suffix));
prefix ^= num[i], suffix ^= num[i];
}
cout << ans << endl;
return 0;
}