1 条题解

  • 0
    @ 2026-10-26 14:35:24

    思路与算法

    设pref[j]是前j次异或和、all为总异或。插入旋转后的最终值为rot(x) XOR (rot(pref[j]) XOR all XOR pref[j])。把括号中的常量全部加入01Trie,设y=rot(x),目标转为max_y min_c(y XOR c)。Trie某位只有一个孩子时,y选相反位强制得1;有两个孩子时对手总能令该位为0,我们选两个子树后续最优值较大的方向,并在并列时累加初值数量。

    正确性说明

    旋转是按位线性且为n位数上的双射,所以上述代数变换不改变最优值或初值数量。XOR比较先看最高不同位:单孩子时取得1严格优于0,选择唯一;双孩子时对手可跟随y同位,使最高位为0,最坏后缀仅由该孩子决定。两分支的y首位不同,最优后缀并列时计数相加不重叠。叶子没有剩余位,恰有1种后缀选择。

    复杂度

    插入m+1个n位常量及遍历Trie总O(n(m+1))时间、同阶空间,前缀数组初始化O(m)。n≤30、m≤10万,最多约300万节点、每节点两个int,计数≤2^30用long long。每次只访问实际节点,重复常量不增加新选择。

    易错点

    旋转时刻包括异或之前与全部异或之后,不能漏pref[0]或pref[m]。求的是最坏时刻后的最大值,不是通常Trie最大异或。独立小n枚举所有初值和全部时刻;大规模两个常量及完整低16位偶校验常量族给出严格闭式值和数量。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    struct Node {
        int ch[2] = {-1, -1};
    };
    vector<Node> tr;
    pair<long long, long long> solve(int u, int bit) {
        if (bit < 0)
            return {0, 1};
        int a = tr[u].ch[0], b = tr[u].ch[1];
        if (a < 0 || b < 0) {
            auto x = solve(a < 0 ? b : a, bit - 1);
            x.first += 1LL << bit;
            return x;
        }
        auto x = solve(a, bit - 1), y = solve(b, bit - 1);
        if (x.first > y.first)
            return x;
        if (y.first > x.first)
            return y;
        return {x.first, x.second + y.second};
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n, m;
        cin >> n >> m;
        vector<unsigned> prefix(m + 1);
        for (int i = 1; i <= m; ++i) {
            unsigned x;
            cin >> x;
            prefix[i] = prefix[i - 1] ^ x;
        }
        if (n == 0) {
            cout << 0 << '\n' << 1 << '\n';
            return 0;
        }
        unsigned mask = (1U << n) - 1;
        auto rotate = [&](unsigned x) {
            return ((x << 1) & mask) | (x >> (n - 1));
        };
        tr.reserve(size_t(m + 1) * n + 1);
        tr.emplace_back();
        for (unsigned p : prefix) {
            unsigned c = rotate(p) ^ prefix.back() ^ p;
            int u = 0;
            for (int bit = n - 1; bit >= 0; --bit) {
                int b = (c >> bit) & 1U;
                if (tr[u].ch[b] < 0) {
                    tr[u].ch[b] = tr.size();
                    tr.emplace_back();
                }
                u = tr[u].ch[b];
            }
        }
        auto ans = solve(0, n - 1);
        cout << ans.first << '\n' << ans.second << '\n';
    }
    
    • 1

    信息

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