传送门:洛谷 CF2218E The 67th XOR Problem | Codeforces E. The 67th XOR Problem
更佳的阅读体验:CF2218E 题解


简要题意:给你一个数组,每次操作可以选择其中一个元素,将数组内所有元素都与它进行按位异或运算,然后将该元素删除,求 $n−1$ 次操作后剩下的最后一个元素可能的最大值。$\sum n \le 3105$。

诈骗题。

来推个柿子吧!假如现在我们有一个 $n = 5$ 的数组 $\{ a_1, a_2, a_3, a_4, a_5 \}$,我们选中第一项进行一次操作,数组就变成了:

$$ \{ a_2 \oplus a_1, a_3 \oplus a_1, a_4 \oplus a_1, a_5 \oplus a_1 \} $$

那如果再对现在的第一次进行一次操作呢?现在数组就变成了:

$$ \{ (a_3 \oplus a_1) \oplus (a_2 \oplus a_1), (a_4 \oplus a_1) \oplus (a_2 \oplus a_1), (a_5 \oplus a_1) \oplus (a_2 \oplus a_1) \} $$

我们知道,异或运算有一个很重要的性质是 $x \oplus x = 0$,同时也满足结合律。因此,现在的每一项都异或了两次 $a_1$,其实 $a_1$ 就被消掉了,现在的数组就变成:

$$ \{ a_3 \oplus a_2, a_4 \oplus a_2, a_5 \oplus a_2 \} $$

我们发现第一次操作中选中的 $a_1$ 已经不存在了。如果我们一直选择序列中的第一项进行操作,最后剩下的一个元素就是 $a_5 \oplus a_4$,也就是,最后一个未被选中的数与最后一次被选中的数的异或值。

因此,我们只需要确定这两个数,就可以得到最后剩下的一个数的值。因为 $n$ 非常小,我们可以直接枚举任意两个元素的异或值,求最大值即可。

单组数据时间复杂度 $O(n^2)$。

#include <iostream>
using namespace std;

const int N = 3110;
int t, n, a[N], ans;

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    for (cin >> t; t; --t) {
        ans = 0;
        cin >> n;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        for (int i = 1; i <= n; ++i)
            for (int j = i + 1; j <= n; ++j) ans = max(ans, a[i] ^ a[j]);
        cout << ans << '\n';
    } return 0;
}
最后修改:2026 年 04 月 16 日
如果觉得我的文章对你有用,请随意赞赏