1.题目大意:
a序列的n个数异或和为:
a
1
a1
a1 xor
a
2
a2
a2 xor
a
3
a3
a3 xor
a
4
a4
a4…xor
a
n
an
an
可以对一段连续的
a
l
.
.
a
r
al..ar
al..ar加一,操作一次或者不操作,求操作之后的n个数的异或和
2.分析题目:
最后一定是前面一部分不加一,中间一部分加一,后面一部分不加一,注意每部分可能长度为0
维护两个前缀数组:
1.
b
[
i
]
维
护
前
i
个
a
[
i
]
+
1
的
异
或
和
b[i]维护前i个a[i]+1的异或和
b[i]维护前i个a[i]+1的异或和
2.
a
[
i
]
维
护
前
i
个
a
[
i
]
的
异
或
和
a[i]维护前i个a[i]的异或和
a[i]维护前i个a[i]的异或和
3.再用字典树维护a[n] ^ a[i] ^ b[i]
为什么要字典树维护a[n]^a[i] ^b[i]呢?
想想,首先异或运算是满足交换律和结合律的
因为
a
[
i
]
a[i]
a[i]维护的是原a数组的前缀异或和,a[i]^a[n]剩下的是原a数组的,a[i+1] ^ a[i+2]…a[n]
b[i] ^ a[i] ^ a[n]为 原a数组的前i个(a[i]+1)异或和再异或原 数组的后面的n-i个a[i]的异或和
即 (a[1]+1) ^ (a[2]+1) ^(a[3]+1) ^ … ^(a[i]+1) ^a[i+1] ^a[i+2] ^… ^ a[n]
遍历一遍将所有的a[i]^a[n] ^b[i]放trie上面
4.再用a[i]^b[i]去查询trie上的最大异或对
为什么是a[i]^b[i]去查询呢?
因为答案一定是某一个 a[x] ^ b[x] ^ (a[n] ^ a[i] ^ b[i])
简单证明一下:
通过3已知,(a[n] ^ a[i] ^ b[i])为:
(a[1]+1) ^ (a[2]+1) ^(a[3]+1) ^ … ^(a[i]+1) ^a[i+1] ^a[i+2] ^… ^ a[n]
(这里的a数组是没有前缀处理的原a数组)
此时a[n] ^ a[i] ^ b[i]再异或b[x]^a[x]
就会将索引为1-x的异或变成0((a[i]+1)^(a[i]+1)),再将索引1-x的异或和变成a[1] ^ a[2] …a[x]
整个a[x] ^ b[x] ^ (a[n] ^ a[i] ^ b[i])变成:
a[1] ^ a[2] ^ …^ a[x] ^ (a[x+1]+1) ^ (a[x+1]+1) ^ (a[x+2]+1) …(a[x+k]+1) ^ a[x+k+1] ^ …a[n]
分成开始说的三段!
接下来就是求最大异或对了!
代码:
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
# define rep(i,be,en) for(int i=be;i<=en;i++)
# define pre(i,be,en) for(int i=be;i>=en;i--)
typedef pair<int, int> PII;
#define ll long long
#define endl "\n"
#define LOCAL
#define pb push_back
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
inline int read()
{
int X = 0;
bool flag = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') flag = 0;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
X = (X << 1) + (X << 3) + ch - '0';
ch = getchar();
}
if (flag) return X;
return ~(X - 1);
}
inline void write(int X)
{
if (X < 0) {
X = ~(X - 1);
putchar('-');
}
if (X > 9) write(X / 10);
putchar(X % 10 + '0');
}
int son[N][3];
int n;
int idx, a[N], b[N];
void insert(int x)
{
int p = 0, u;
for (int i = 31; i >= 0; i--)
{
u = (x >> i) & 1;
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
}
int query(int x)
{
int p = 0, u;
int res = 0;
for (int i = 31; i >= 0; i--)
{
u = (x >> i) & 1;
if (son[p][u ^ 1]) res += 1 << i, p = son[p][u ^ 1];
else
p = son[p][u];
}
return res;
}
void solve()
{
n = read();
rep(i, 1, n)
{
a[i] = read();
b[i] = a[i] + 1;
}
for (int i = 1; i <= n; i++)
{
a[i] ^= a[i - 1];
b[i] ^= b[i - 1];
}
for (int i = 0; i <= n; i++)
{
int x = a[n] ^ a[i] ^ b[i];
insert(x);
}
int ans = 0;
for (int i = 0; i <= n; i++)
ans = max(ans, query(b[i] ^ a[i]));
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio;
cin.tie(0);
cout.tie(0);
//#ifdef LOCAL
//freopen("data.in.txt","r",stdin);
//freopen("data.out.txt","w",stdout);
//#endif
int T = 1;
//scanf("%d",&T);
while (T--)
{
solve();
}
return 0;
}
撰文不易,点个赞再走吧!