[模板]线性基
luogu
给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大。
\(1\le n \le 50,0\le S_i \le 2^{50}\)
线性基
线性基其实就是构造出一组序列\(p_0,p_1...p_n\),使得从这些数中任选一个子集的异或和的值域同等与从原序列中任选一个子集的异或和的值域。
同时保证:\(p_i\)在二进制下的最高位是\(2^i\)。
这样在求异或和最大的时候就可以按位贪心了。
构造方法:对于一个需要插入线性基的数\(x\),首先找到它在二进制下的最高位\(i\),检查\(p_i\)是否已经生成。若尚未生成则令\(p_i=x\)并结束操作,否则令\(x=x\ \rm xor\ p_i\),并继续插入操作。
放一段线性基的代码:
struct xxj{
ll p[70];
void insert(ll x)
{
for (int j=63;j>=0;--j)
{
if (!(x>>j)) continue;
if (!p[j]) {p[j]=x;return;}
x^=p[j];
}
}
ll query(ll x)
{
for (int j=63;j>=0;--j)
x=max(x,x^p[j]);
return x;
}
}S;
其中\(\rm query(x)\)是查询异或上\(\rm x\)后的最大值,如果要直接查最大值的话直接\(\rm query(0)\)就好了。
线性基的合并
两个线性基是可以合并的。只要把其中一个暴力插入到另一个里面就行了。
xxj merge(xxj a,xxj b)
{
for (int j=63;j>=0;--j) if (b.p[j]) a.insert(b.p[j]);
return a;
}
合并的复杂度是\(O(\log^2n)\)的。