AtCoder Beginner Contest 141 F 题解(线性基)

题意:

给你n个数字,划分为两个集合,他们的异或和分别为x和y,求x+y的最大值。

题解:

原本的异或和为sum,题目可以理解成从n个数字中取出一个集合,这个集合的异或和为x,使得sum^x + x最大。那么对于sum中原本为0的位,如果x的这一位取1,sum ^ x的这一位也会取1,在两个地方都有收益,而sum原本为1的位,x这一位取0还是取1,结果这一位都只有一个1。我们可以用线性基来获得原本集合的二进制基底。但是我们发现光是从高到低,遇到sum为0就取这一位的线性基,遇到1就不管是不对的:因为虽然sum的这一位是1,但是它还有可能影响后面sum为0的位。我们要优先考虑sum中原本为0的位,使得x该位取为1,那么我们可以改变线性基的优先级,让sum中为0的优先级更高,这样sum为1的位就不会影响sum为0的位了,至此我们可以贪心。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 50;
ll p[64];
int st[64];
int tot = 0;
void ins(ll x){
    for(int i = 0; i < tot; ++i){
        if((x>>st[i])&1){
            if(p[i]) x^=p[i];
            else {p[i] = x;
            break;}
        }
    }
}
int n;
ll a[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    ll sum = 0;
    for(int i = 0; i < n ; ++i) cin>>a[i], sum^=a[i];
    for(int i = 60; i >= 0; --i) if(!((sum>>i)&1)) st[tot++] = i;
    for(int i = 0; i < n; ++i) ins(a[i]);
    ll res = 0;
    for(int i = 0; i < tot; ++i)
        if(!((res>>st[i])&1)) res ^= p[i];
    cout<< res + (sum^res)<<endl;
}
/*
4
23 36 66 65
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值