1 条题解

  • 0
    @ 2026-10-27 13:20:35

    思路与算法

    先从左扫描。令前缀异或P_i=A_1异或...异或A_i,任何以i结尾的区间异或为P_i异或P_j(j<i)。把历史P_j插入31层二进制Trie,查询与P_i异或最大的值,维护截至i的最大区间异或left[i]。从右对称得到right[i]。最后枚举两段之间的分割点i,最大化left[i]+right[i+1]。

    正确性说明

    前缀异或抵消公共部分,故历史前缀查询恰涵盖所有以i结尾的非空区间。Trie从高位到低位优先选择相反位,是因为较高位的一位增益大于全部低位总和,因此查询最优。左右扫描取前缀或后缀最大值正确。任意合法两段之间至少有一个分割点,其值不超过该点左右最优之和;反过来每个分割点的两个最优区间必然非空且不交,故取最大值恰为答案。

    复杂度

    每次插入和查询31层,两个方向总O(31N),包括数组和Trie节点初始化;枚举分割点O(N)。空间O(31N),两次扫描复用同一Trie容量。

    易错点

    先查询再插入当前前缀,避免只靠空区间取值;初始插入0。两个子数组均须非空,分割点只能到N-1。两段和可达2^32-2,应使用64位输出。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    struct Trie {
        vector<array<int, 2>> t;
        Trie(int n) {
            t.reserve(min(31LL * n + 1, 14000000LL));
            clear();
        }
        void clear() {
            t.clear();
            t.push_back({{0, 0}});
        }
        void add(unsigned x) {
            int v = 0;
            for (int k = 30; k >= 0; k--) {
                int b = x >> k & 1;
                if (!t[v][b]) {
                    t[v][b] = t.size();
                    t.push_back({{0, 0}});
                }
                v = t[v][b];
            }
        }
        unsigned get(unsigned x) {
            int v = 0;
            unsigned ans = 0;
            for (int k = 30; k >= 0; k--) {
                int b = x >> k & 1;
                if (t[v][b ^ 1]) {
                    ans |= 1U << k;
                    v = t[v][b ^ 1];
                } else
                    v = t[v][b];
            }
            return ans;
        }
    };
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        if (!(cin >> n))
            return 0;
        vector<unsigned> a(n), l(n), r(n);
        for (auto &x : a)
            cin >> x;
        Trie t(n);
        t.add(0);
        unsigned x = 0, best = 0;
        for (int i = 0; i < n; i++) {
            x ^= a[i];
            best = max(best, t.get(x));
            l[i] = best;
            t.add(x);
        }
        t.clear();
        t.add(0);
        x = best = 0;
        for (int i = n - 1; i >= 0; i--) {
            x ^= a[i];
            best = max(best, t.get(x));
            r[i] = best;
            t.add(x);
        }
        unsigned long long ans = 0;
        for (int i = 0; i + 1 < n; i++)
            ans = max(ans, (unsigned long long)l[i] + r[i + 1]);
        cout << ans << '\n';
    }
    
    • 1

    信息

    ID
    2107
    时间
    1000ms
    内存
    128MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者