题目链接:点击这里
Problem: 异星工厂
Time limit: 2s Mem limit: 1000 MB AC/Submission: 19/111 Discuss
Problem Description
在遥远的外太空,一位勇敢的探险家God Ma在宇宙中探索,不幸的是,他的飞船遭遇了太空风暴,飞船坠毁在了一个未知的星球。
由于没有足够的资源修复飞船,所以他需要采集一些资源,建造卫星,向他的小伙伴求救。
经过God Ma的探查,他找到了一条长度N为的资源带,资源带的每个点每秒都能产生一定量的资源物质Ai,资源物质需要用收集器来收集。
现在God Ma手里有两个收集器,每个收集器可以覆盖一个长度任意的区间,收集器的覆盖区间不能重叠,因为会发生碰撞。
虽然收集器的覆盖范围十分厉害,但是有一个缺点,在同一时刻收集器并不能收集所有的资源,只能收集到区间每个点资源量的异或值,若收集器覆盖的区间为[l,r],则一秒内能收集到的资源为(A[l] ^ A[l+1] …… ^ A[r])
由于God Ma想尽快发送求救信号,你能帮他计算出两个收集器每秒能够收集的资源之和最多是多少吗。
Input
多组数据。
第一行一个N(1 <= N <= 100000),表示资源带的长度
第二行N个数Ai(1 <= Ai <= 2^30),表示每个点上每秒产生的资源量
Output
每组数据输出一行,一个整数,表示两个收集器每秒能够收集的最大资源量。
Sample Input
5
1 2 3 1 2
Sample Output
6
题意:在一个数列中求两段使得每一段的异或再求和的结果最大.
很容易想到用前缀来搞,先把每一段的前缀异或和后缀异或,然后用字典树爬出每一个下标为结尾或者开头的最大异或子段的值,最后枚举分界点,在分界点左侧和右侧分别取一个最大的异或子段,更新最大值就好了.
#include <bits/stdc++.h>
using namespace std;
#define maxn 111111
int a[maxn], n;
struct node {
int next[2];
}tree1[maxn*33], tree2[maxn*33];
int cnt1, cnt2;
int pre[maxn], la[maxn];
int l[maxn], r[maxn];
struct one {
int num, id;
bool operator < (const one &a) const {
return num < a.num || (num == a.num && id < a.id);
}
};
set <one> gg;
set <one>::iterator it;
int root1, root2;
int new_node1 () {
cnt1++;
tree1[cnt1].next[0] = tree1[cnt1].next[1] = -1;
return cnt1;
}
int new_node2 () {
cnt2++;
tree2[cnt2].next[0] = tree2[cnt2].next[1] = -1;
return cnt2;
}
void insert1 (int root, int num) {
int p = root;
for (int bit = 30, i = (1<<30); bit >= 0; i >>= 1, bit--) {
int id = ((num&i)>0);//这一位是不是1
if (tree1[p].next[id] == -1) {
tree1[p].next[id] = new_node1 ();
}
p = tree1[p].next[id];
}
}
void insert2 (int root, int num) {
int p = root;
for (int bit = 30, i = (1<<30); bit >= 0; i >>= 1, bit--) {
int id = ((num&i)>0);//这一位是不是1
if (tree2[p].next[id] == -1) {
tree2[p].next[id] = new_node2 ();
}
p = tree2[p].next[id];
}
}
int find1 (int root, int num) {
int p = root;
int ans = 0;
for (int bit = 30, i = (1<<30); bit >= 0; i >>= 1, bit--) {
int id = (((num&i)>0)^1);//这一位的值^1
if (tree1[p].next[id] != -1) {
ans = (ans^i);//这一位可以为1
p = tree1[p].next[id];
}
else
p = tree1[p].next[id^1];
}
return ans;
}
int find2 (int root, int num) {
int p = root;
int ans = 0;
for (int bit = 30, i = (1<<30); bit >= 0; i >>= 1, bit--) {
int id = (((num&i)>0)^1);//这一位的值^1
if (tree2[p].next[id] != -1) {
ans = (ans^i);//这一位可以为1
p = tree2[p].next[id];
}
else
p = tree2[p].next[id^1];
}
return ans;
}
int main () {
while (scanf ("%d", &n) == 1) {
for (int i = 1; i <= n; i++) {
scanf ("%d", &a[i]);
}
gg.clear ();
pre[0] = 0;
for (int i = 1; i <= n; i++) {
pre[i] = pre[i-1]^a[i];
}
la[n+1] = 0;
for (int i = n; i >= 1; i--) {
la[i] = la[i+1]^a[i];
}
cnt1 = cnt2 = 0;
root1 = new_node1 ();
root2 = new_node2 ();
insert1 (root1, 0), insert2 (root2, 0);
for (int i = 1; i <= n; i++) {
int num = find1 (root1, pre[i]);
l[i] = num;
insert1 (root1, pre[i]);
}
for (int i = n; i >= 1; i--) {
int num = find2 (root2, la[i]);
r[i] = num;
insert2 (root2, la[i]);
}
for (int i = 2; i <= n; i++) {
l[i] = max (l[i], l[i-1]);
}
for (int i = n-1; i >= 1; i--) {
r[i] = max (r[i], r[i-1]);
}
long long ans = l[-1];
for (int i = 1; i < n; i++) {
ans = max (ans, 1LL*l[i]+r[i+1]);
}
printf ("%lld\n", ans);
}
return 0;
}