链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11008
题意:给定n个数,求一段连续的数是的他们的异或和最大。1<=n<=10^5
题解:在trie树上搞。首先预处理出sum[i]表示前i个数的异或和,那么第i个到第j个异或和就是sum[j]^sum[i-1]。然后可以建立一个高度为32的二叉字典树,每个节点的左儿子是0,右儿子是1。把sum[0]插入trie树中。枚举i,对于sum[i],从trie树的根节点出发,贪心的往前位异或值为1的方向头,更新答案,然后将sum[i]插入trie树中。很容易证明这个算法是对的。
代码君:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int maxn = 100010;
struct Node {
Node *next[2];
};
int tot = 0, n, a[maxn];
Node pool[maxn*40], *root;
Node *newNode() {
Node *p = &pool[tot++];
memset(p->next, 0, sizeof(p->next));
return p;
}
void init() {
tot = 0;
root = newNode();
}
void insert(int x) {
Node *cur = root;
for (int i = 30; i >= 0; i--) {
if (x & (1 << i)) {
if (cur->next[1] == NULL)
cur->next[1] = newNode();
cur = cur->next[1];
} else {
if (cur->next[0] == NULL)
cur->next[0] = newNode();
cur = cur->next[0];
}
}
}
int query(int x) {
Node *cur = root;
int res = 0;
for (int i = 30; i >= 0; i--) {
if (x & (1 << i)) {
if (cur->next[0]) {
res |= (1 << i);
cur = cur->next[0];
} else {
cur = cur->next[1];
}
} else {
if (cur->next[1]) {
res |= (1 << i);
cur = cur->next[1];
} else {
cur = cur->next[0];
}
}
}
return res;
}
int main() {
int test;
scanf("%d", &test);
for (int cas = 1; cas <= test; cas++) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] ^= a[i-1];
}
int ans = 0;
init();
for (int i = 0; i < n; i++) {
insert(a[i]);
ans = max(ans, query(a[i+1]));
}
printf("%d\n", ans);
}
return 0;
}