题解 [2017 山东一轮集训 Day1 / SDWC2018 Day1] Set
先来进行一些口胡:
先考虑怎么最大化 \(x_1+x_2\)
将所有数扔进一个线性基里,逐位确定 \(x_1\)
这要求 \(x_1\) 能被拼出来,那么仅针对这个限制每一位可能是只能选某一种或两个都可以选
考虑都可以选的情况,此时最大化 \(x_1+x_2\) 的方法是最大化这一位上的和
同时注意最小化 \(x_1\) 这一位上的值
不知道有没有正确性
然后正解:
我忽略了一个事情:
假如当前某一位异或和为 1
为了最小化 \(x_1\) 我会选择让 \(x_1\) 的这一位为 0
但是这样可能就减少了低位的选法,可能导致无法在低位最大化 \(x_1+x_2\)
所以正确做法是对所有位重排优先级
异或和相同的高位 > 低位,不同的异或和为 0 的 > 异或和为 1 的
复杂度 \(O(n\log V)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
int ord[N], top;
ll a[N], base[N], sum, ans;
void ins(ll val) {
for (int i=1; i<=top; ++i) if (val&(1ll<<ord[i])) {
if (!base[i]) {base[i]=val; return ;}
else val^=base[i];
}
}
signed main()
{
n=read();
for (int i=1; i<=n; ++i) sum^=(a[i]=read());
for (int i=62; ~i; --i) if (!(sum&(1ll<<i))) ord[++top]=i;
for (int i=62; ~i; --i) if (sum&(1ll<<i)) ord[++top]=i;
for (int i=1; i<=n; ++i) ins(a[i]);
for (int i=1; i<=top; ++i) {
if (sum&(1ll<<ord[i])) {
if (ans&(1ll<<ord[i]) && base[i]) ans^=base[i];
}
else {
if (!(ans&1ll<<ord[i]) && base[i]) ans^=base[i];
}
}
printf("%lld\n", ans);
return 0;
}