题解 P3812 【【模板】线性基】
刚刚口胡并学了线性基,就来写篇题解,记录一下。
从
既然是异或和,因为异或是位运算,肯定要用到二进制的。
考虑异或和的性质:对于这一位,有奇数个
但因为每一位二进制位可能有很多
但是我太菜了发现并不会构造,怎么办呢?上百度搜线性基正解吧。
结果一搜发现我已经口胡出来了,愣是傻傻的不会构造 /jk /jk,那就继续说吧。
线性基就是由原数列集合构造出的满足下面性质的集合:
- 线性基内的元素可以通过求异或和,得到原集合的元素任意求异或和得到的所有值。
- 线性基是满足上面性质的最小的集合。
- 线性基不存在异或和为
0 的子集。 - 线性基中,任取不同的子集求异或和,得到的答案不同。(即线性基子集的异或和具有唯一性)
- 线性基内所有元素的二进制最高位互不相同。
考虑进行构造:
在线性基插入元素
要查询最大值,从高位到低位枚举线性基中最高位为该位的元素,如果答案异或上这个数比原来的答案大,更新答案。这样因为更低位的结果无法影响当前位,因此这一方法是最优的。
代码:
//By: Luogu@rui_er(122461)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 55, bit = 50;
ll n, a, p[N];
void insert(ll k) {
for(ll i=bit;i>=0;i--) {
if(!(k&(1LL<<i))) continue;
if(!p[i]) return p[i] = k, void();
k ^= p[i];
}
}
ll maxXor() {
ll res = 0;
for(ll i=bit;i>=0;i--) res = max(res, (res^p[i]));
return res;
}
int main() {
scanf("%lld", &n);
while(n--) {scanf("%lld", &a); insert(a);}
printf("%lld\n", maxXor());
return 0;
}