1 条题解

  • 0
    @ 2026-10-27 13:36:01

    思路与算法

    AND:从高位到低位试加答案位,若至少两个数包含当前候选所有位就保留。XOR:把前面的数放二进制字典树,当前数每位优先走相反分支。OR:设freq为数值频次,子集zeta得C[M]=落在M子集中的数个数;C[M]²计有序配对的OR为M子集的数量,Möbius反演得每个精确OR结果的配对数,扣除相同下标,再找最高非零结果。

    正确性说明

    AND候选可行等价于至少两数同时包含它,按高位优先贪心保证最大整数。XOR每一位的1优先于所有低位,因此字典树逐位选相反分支最优,且只查先前数保证下标不同。两数OR为M子集当且仅当两数均为M子集,故zeta后的平方是正确累计配对数;Möbius逆变换恢复精确结果。自配对OR就是自身值,扣freq后恰留下不同下标配对,取最大有配对结果即可。

    复杂度

    B=20。AND与XOR各O(NB)时间;OR为O(B2^B+N),数组初始化O(2^B)。XOR空间O(NB),OR空间O(2^B),AND除输入外O(1)。最多T6组顺序释放。

    易错点

    c2才是xor、c3是or。相同数值但不同下标允许;OR要扣自配对,XOR查询前先插入会误用自身。变换中计数平方达10^10,使用64位。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    const int B = 20, S = 1 << B;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int T;
        cin >> T;
        while (T--) {
            int n, c;
            cin >> n >> c;
            vector<int> a(n);
            for (int &x : a)
                cin >> x;
            int ans = 0;
            if (c == 1) {
                for (int k = B - 1; k >= 0; k--) {
                    int z = ans | (1 << k), cnt = 0;
                    for (int x : a)
                        cnt += (x & z) == z;
                    if (cnt >= 2)
                        ans = z;
                }
            } else if (c == 2) {
                vector<array<int, 2>> tr(1, {{-1, -1}});
                for (int x : a) {
                    if (tr.size() > 1) {
                        int u = 0, z = 0;
                        for (int k = B - 1; k >= 0; k--) {
                            int b = x >> k & 1;
                            if (tr[u][b ^ 1] >= 0) {
                                z |= 1 << k;
                                u = tr[u][b ^ 1];
                            } else
                                u = tr[u][b];
                        }
                        ans = max(ans, z);
                    }
                    int u = 0;
                    for (int k = B - 1; k >= 0; k--) {
                        int b = x >> k & 1;
                        if (tr[u][b] < 0) {
                            tr[u][b] = tr.size();
                            tr.push_back({{-1, -1}});
                        }
                        u = tr[u][b];
                    }
                }
            } else {
                vector<ll> f(S);
                for (int x : a)
                    f[x]++;
                for (int d = 1; d < S; d <<= 1)
                    for (int base = 0; base < S; base += d * 2)
                        for (int j = 0; j < d; j++)
                            f[base + d + j] += f[base + j];
                for (ll &x : f)
                    x *= x;
                for (int d = 1; d < S; d <<= 1)
                    for (int base = 0; base < S; base += d * 2)
                        for (int j = 0; j < d; j++)
                            f[base + d + j] -= f[base + j];
                for (int x : a)
                    f[x]--;
                for (int x = S - 1; x >= 0; x--)
                    if (f[x]) {
                        ans = x;
                        break;
                    }
            }
            cout << ans << '\n';
        }
    }
    
    • 1

    信息

    ID
    2119
    时间
    1500ms
    内存
    128MiB
    难度
    提高
    标签
    递交数
    0
    已通过
    0
    上传者