SPOJ 8217 XMAX - XOR Maximization 题解

题意:对于集合 S = {   a 1 , a 2 , … , a n   } S = \set{a_1, a_2, \dots, a_n} S={a1,a2,,an} ,设 X ( S ) = a 1 ⊕ a 2 ⊕ ⋯ ⊕ a n X(S) = a_1 \oplus a_2 \oplus \dots \oplus a_n X(S)=a1a2an ⊕ \oplus 表示异或)。给定 S = {   a 1 , a 2 , … , a n   } S = \set{a_1, a_2, \dots, a_n} S={a1,a2,,an} ,求 max ⁡ T ⊆ S X ( T ) \max_{T \subseteq S} X(T) maxTSX(T)

因为 a i < 2 60 a_i < 2^{60} ai<260 ,所以设 a i a_i ai 的二进制形式为 b i , 59 b i , 58 … b i , 1 b i , 0 ‾ \overline{b_{i, 59}b_{i, 58} \dots b_{i, 1}b_{i, 0}} bi,59bi,58bi,1bi,0 ,设 c k c_k ck 表示满足 b i , k = 1 b_{i, k} = 1 bi,k=1 i i i 的个数。如果 c k c_k ck 是奇数,则 X ( S ) X(S) X(S) 一定包含 2 k 2^k 2k 位。

因为一个数异或自身等于零,所以我们可以允许每个数使用多次,进而可知,用 a i ⊕ a j a_i \oplus a_j aiaj 替换 a j a_j aj a i a_i ai 不变)对结果也没有影响,也不会影响 b b b 1 1 1 的个数的奇偶性,我们称这种替换为“合法替换”。而且,对 S S S 的任意子集 T T T ,都可以对 S S S 进行若干次“合法操作”得到 S ′ S' S ,使得 X ( S ′ ) = X ( T ) X(S') = X(T) X(S)=X(T)

设命题 p k p_k pk 为真当且仅当 ∃ i , b i , k = 1 ∧ ∀ l > k , b i , l = 0 \exists i, b_{i, k} = 1 \land \forall l > k, b_{i, l} = 0 i,bi,k=1l>k,bi,l=0 。我们可以借助类似高斯消元的方法对 S S S 中的元素进行若干次“合法替换”,使得 S S S(严谨表示应该用 S ′ S' S ,但为了方便仍使用 S S S )满足:

  • ∀ k , p k → c k = 1 \forall k, p_k \to c_k = 1 k,pkck=1
  • 如果 p k p_k pk 为假,则无法通过若干次“合法替换”使 p k p_k pk 为真。
  • 如果 c k c_k ck 为偶数,那么如果经过若干次“合法替换”使 c k c_k ck 为奇数,则必然存在 l > k l > k l>k 使得 c l c_l cl 从奇数变为偶数。

此时, X ( S ) X(S) X(S) 就是所求的最大值,因为如果继续“合法替换”,即使将 c k c_k ck 从偶数变为奇数,也一定会牺牲更高位,得不偿失。

代码:

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

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<ll> a(n);
    for (ll &i : a)
        cin >> i;
    for (int row{}, col{59}, pivot; col >= 0; --col)
    {
        for (pivot = row; pivot < n && ~a[pivot] >> col & 1; ++pivot)
            ;
        if (pivot < n)
        {
            swap(a[row], a[pivot]);
            for (int i{}; i < n; ++i)
                if (i != row && a[i] >> col & 1)
                    a[i] ^= a[row];
            ++row;
        }
    }
    ll ans{};
    for (ll &i : a)
        ans ^= i;
    cout << ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值