题目描述
难度分:2200
输入n(1≤n≤105)和长为n的数组a(0≤a[i]≤1012)。
选择a的一个前缀(可以为空)和一个后缀(可以为空),要求前缀后缀不相交。
输出所选数字的异或和的最大值。
输入样例1
2
1 2
输出样例1
3
输入样例2
3
1 2 3
输出样例2
3
输入样例3
2
1000 1000
输出样例3
1000
算法
枚举+01
字典树按位贪心
这个题的思路比较简单,其实就是“算法基础课最大异或对”那个题的拓展,先将所有的后缀异或和(sufXori=⊕nk=ia[k],i∈[1,n],注意还要放入一个0,防止后缀为空的情况)都放到一个01
字典树中。并给字典树实现一个特殊的search函数,search(x)查询的是字典树中所有元素与x异或能够得到的最大值,这个函数的原理就是最大异或对那个题按位贪心的思路。
然后枚举前缀,注意到前缀和后缀是可以为空的,先初始化答案ans为“前缀为空”与“后缀为空”时的较大值。然后考虑前后缀都不为空的情况,枚举前缀的右端点i,当遍历到a[i]时,设此时的前缀异或和为preXor=⊕ik=1a[k],将sufXori从字典树中删除以保证前后缀不重叠,维护ans与search(preXor)的最大值即可。
复杂度分析
时间复杂度
01
字典树的插入,删除和查询都是较大的常数操作,仅与数字的二进制位有关,本题的数据范围在1012以内,因此迭代的深度最大不会超过k=40,这个常数操作的时间复杂度为O(k)。枚举所有前缀的时间复杂度为O(n),因此算法整体的时间复杂度也为O(kn)。
空间复杂度
最差情况下每个数a[i]都需要40个位来存储,因此额外空间复杂度为O(kn)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
LL a[N];
int n;
class TrieNode {
public:
int pass;
TrieNode* next[2];
TrieNode() {
pass = 0;
next[0] = NULL;
next[1] = NULL;
}
};
class Trie {
public:
const int HEIGHT = 41;
TrieNode* root = new TrieNode();
void insert(LL x) {
TrieNode* cur = root;
for(int i = HEIGHT; i >= 0; i--) {
int bit = x>>i&1;
if(cur->next[bit] == NULL) {
cur->next[bit] = new TrieNode();
}
cur = cur->next[bit];
cur->pass++;
}
}
void erase(LL x) {
TrieNode* cur = root;
for(int i = HEIGHT; i >= 0; i--) {
int bit = x>>i&1;
if(cur->next[bit]->pass-- == 1) {
cur->next[bit] = NULL;
return;
}
cur = cur->next[bit];
}
}
LL search(LL x) {
TrieNode* cur = root;
LL y = 0;
for(int i = HEIGHT; i >= 0; i--) {
int bit = x>>i&1;
if(cur->next[1 - bit]) {
y = (y<<1ll) + (1 - bit);
cur = cur->next[1 - bit];
}else {
y = (y<<1ll) + bit;
cur = cur->next[bit];
}
}
return x^y;
}
};
int main() {
scanf("%d", &n);
LL ans = 0;
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
ans ^= a[i];
}
LL suf_xor = 0;
Trie* trie = new Trie();
trie->insert(suf_xor);
for(int i = n; i >= 1; i--) {
suf_xor ^= a[i];
trie->insert(suf_xor);
}
LL pre_xor = 0;
ans = max(ans, trie->search(0));
for(int i = 1; i < n; i++) {
pre_xor ^= a[i];
trie->erase(suf_xor);
suf_xor ^= a[i];
ans = max(ans, trie->search(pre_xor));
}
printf("%lld\n", ans);
return 0;
}