2026牛客暑期多校2 B题思路分享

题意

给定 \(n\) 个数,分成两个集合,最大化两集合内元素异或和之和.

\(1 \le n \le 5\times 10^5\).

思路

令所有元素异或和为 \(s\),第一个集合异或和为 \(x\),则 \(ans = x+(x\oplus s)\),考虑将 \(x\) 化成一项.

根据公式 \(a+b = a\oplus b + 2(a \And b)\)\(ans = s+2(x \And (s\oplus x))\).

\(x \And (s\oplus x)\) 用真值表发现可以化成 \(x\And \sim s\),因此 \(ans = s+2(x\And \sim s)\),要最大化 \(x\And \sim s\).

因为 \((\bigoplus{a_i})\And b = \bigoplus{(a_i \And b)}\),对于所有给定的元素,全部 \(\And \sim s\) 后插入线性基,之后就是标准的线性基求最大值.

时间复杂度 \(\mathcal{O}(n\log V)\)\(V\) 是值域.

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;


void solve(){
    int n;
    cin >> n;

    vector<int> a(n+1);
    int s = 0;
    for (int i=1;i<=n;i++){
        cin >> a[i];
        s^=a[i];
    }

    vector<int> f(31);
    auto insert = [&](int x){
        for (int i=30;i>=0;i--){
            if (x>>i&1){
                if (f[i]==0){
                    f[i] = x;
                    break;
                }
                x^=f[i];
            }
        }
    };

    int m = ((1<<30)-1)^s;
    for (int i=1;i<=n;i++){
        insert(a[i]&m);
    }

    int mx = 0;
    for (int i=30;i>=0;i--){
        mx = max(mx,mx^f[i]);
    }

    cout << s+2*mx << '\n';
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-07-22 17:01  kzssCCC  阅读(4)  评论(0)    收藏  举报