北京师大二附中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\) 使得区间异或和最大

\[Max\{A_j \oplus A_{j+1} \oplus ... \oplus A_i\} \]

等价于

\[Max\{preXor_i \oplus preXor_{j-1}\} \]

对于每次枚举的 \(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\) , 那么也就是说对于两个区间

\[BestLeft_i = Max\{BestLeft_{i-1}, Rxor_{i}\} \]

\[BestRight_i = Max\{BestRight_{i+1}, Lxor_{i}\} \]

这一步可以在计算 \(Lxor, Rxor\) 顺手干了, 复杂度\(O(n)\)

加下来就是枚举分割点 \(i \in [1, n - 1]\)

\[ans = Max{BestLeft[i] + BestRight[i + 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;
}
posted @ 2025-08-25 22:59  txp2025  阅读(8)  评论(0)    收藏  举报