北京师大二附中OnlineJudge-17111
题目描述

slove
明显的 Xor 满足交换律, 故可以构造前缀和数组 \(preXor\)
令对于 \(i \in [1,n]\) , \(preXor_i = preXor_{i-1} \oplus A_i\)
特别的, 令 \(preXor_0 = 0\)
要求两个子区间不相交且顺序不重叠, 那么从不重叠可以知道 \(r_1 < l_2\) 那么也就是说对于两个区间,我们只需要确定 \(r_1 < l_2\) 就可以满足约束条件,对于 \(l_1, r_2\) 是无所谓的。 那可以预处理出对于下标 \(i\), 当下标 \(i\) 作为 \(r_1\) 或 \(l_2\), 区间的最大异或和
令 \(Lxor_i\) 为区间左端点为 \(i\)时 的区间的最大异或和, \(Rxor_i\) 为区间右端点为 \(i\)时 的区间的最大异或和,
那么问题转化为, 对于固定左(右)端点区间,如何求出区间最大异或和?
以左区间为例
我们知道 Xor 可以构造前缀和 , 那么对与目标右端点 \(i\) 要求出最大的 \(j\) 使得区间异或和最大
等价于
对于每次枚举的 \(i\), \(preXor_i\)是已知的,就简化为了求合适的 \(preXor_{j-1}\) , 可使用01字典树解决。
复杂度 \(O(2*n*32)\)
那么现在已知对于每个 \(i\) 作为左(右)端点的区间的最大异或和, 现在可以枚举 \(r_1, l_2\) 作为端点, 复杂度 \(O(n^2)\) , 太大了
如何优化?
记 \(Xor(l, r) = preXor_r \oplus preXor_{l-1}\)
对于右区间 \([l, r]\) 如果存在区间 \([l', r']\), 满足 \(l < l'\) 且 \(Xor(l, r) < Xor(l', r')\), 那么 \([l, r]\) 是没有意义的, 即对 \(Lxor_l\) 的枚举是无意义的,那尝试记录从 \(i\) 往左(右)的所有 \(j\) 的最大区间异或和,为\(BestLeft, BestRight\) , 那么也就是说对于两个区间
这一步可以在计算 \(Lxor, Rxor\) 顺手干了, 复杂度\(O(n)\)
加下来就是枚举分割点 \(i \in [1, n - 1]\)
问题就解决了
#pragma once
#include <vector>
#include <string.h>
#include <algorithm>
#include <numeric>
#include <ctype.h>
#include <cstdarg>
#include <climits>
#include <time.h>
#define _FREAD true
#define MAX_INF 1e18
#define MAX_NUM_SIZE 35
#define MAXN (size_t)(4e5+5)
#define GET_BIT(x, y) ((x >> (31-y)) & 1)
typedef unsigned int uint;
typedef long long int ll;
typedef unsigned long long int ull;
//快读函数声明
template< typename Type >
inline Type fread(Type* p = nullptr);
//快速输出函数
template<typename Type>
inline void fwrite(Type x);
template<size_t _SIZE_SUM>
struct Trie {
struct _Trie_node {
uint ind[2]; //子节点下标
_Trie_node() {
memset(ind, 0, sizeof(ind));
return;
}
};
_Trie_node _trie[_SIZE_SUM];
size_t trie_cnt = 0;
//贪心的,从高往第插入
void insert(ll pos, ll val, ll deep);
ll query(ll pos, ll val, ll cnt);
inline void clear();
Trie() = default;
};
Trie<32 * MAXN> trie;
ll preXor[MAXN], bestL[MAXN], bestR[MAXN]; //[0,i]内左端点的区间的最大异或和 [i,n]内右端点的区间的最大异或和
ll n, ans = 0;
template<size_t _SIZE_SUM>
ll Trie<_SIZE_SUM>::query(ll pos, ll val, ll cnt) {
//2中情况
if (cnt == 32) {
return 0;
}
ll res = 0, temp = GET_BIT(val, cnt);
if (_trie[pos].ind[GET_BIT(val, cnt) ^ 1]) {
res += (1 << (31 - cnt));
res += query(_trie[pos].ind[GET_BIT(val, cnt) ^ 1], val, cnt + 1);
}
else {
res += query(_trie[pos].ind[GET_BIT(val, cnt)], val, cnt + 1);
}
return res;
}
template<size_t _SIZE_SUM>
void Trie<_SIZE_SUM>::insert(ll pos, ll val, ll deep) {
if (deep == 32) {
return;
}
ll res = 0;
if (!_trie[pos].ind[GET_BIT(val, deep)]) {
_trie[pos].ind[GET_BIT(val, deep)] = ++trie_cnt;
}
insert(_trie[pos].ind[GET_BIT(val, deep)], val, deep + 1);
return;
}
template<size_t _SIZE_SUM>
inline void Trie<_SIZE_SUM>::clear() {
std::fill(_trie, _trie + trie_cnt + 1, _Trie_node());
trie_cnt = 0;
return;
}
int main() {
freopen("input.txt", "r", stdin);
fread(&n);
for (size_t i = 1; i <= n; i++) {
ll temp = fread<ll>();
preXor[i] = preXor[i - 1] ^ temp;
}
trie.insert(0, 0, 0);
for (size_t i = 1; i <= n; i++) {
bestR[i] = std::max(bestR[i - 1], trie.query(0, preXor[i], 0));
trie.insert(0, preXor[i], 0);
}
trie.clear();
trie.insert(0, 0, 0);
for (size_t i = n; i >= 1; --i) {
bestL[i] = std::max(bestL[i + 1], trie.query(0, preXor[n] ^ preXor[i - 1], 0));
trie.insert(0, preXor[n] ^ preXor[i - 1], 0);
}
for (size_t i = 1; i < n; i++) {
ans = std::max(ans, bestR[i] + bestL[i + 1]);
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号