题解 [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;
}
posted @ 2022-06-10 07:50  Administrator-09  阅读(1)  评论(0编辑  收藏  举报