「笔记」线性基
作者:互联网
概念
线性基是向量空间的一组基,通常可以解决有关异或的一些题目。-Oi-wiki
线性基就是一个有着特殊性质的集合,在处理某些情况下的异或问题有着意想不到的效果。
假设我们用 \(p\) 数组来存线性基。
线性基可以由给出的一组元素相互异或而来。
而 \(p_i\) 中的元素表示该元素二进制下 \(1\) 的最高位是第 \(i\) 位。
性质
- 线性基具有普通集合所具有的性质,即确定性、互异性、无序性。
- 线性基中每个元素的最高位不同。(根据 \(p\) 数组定义比较显然。)
- 线性基中没有异或和为 \(0\) 的子集。(每个元素的最高位不同,异或起来最高位一定不会为 \(0\)。)
- 线性基中任意多元素的异或和的值域等于原集合中任意多元素的异或和的值域。
- 线性基在满足上一个条件的情况下,所包含元素个数是最少的。
- 线性基中不同的元素异或出来的值是不同的。
构造
一下情况都是在二进制下进行。
假设插入一个元素 \(x\) 。
- 从高位向低位判断,直到遇到该元素某位上为 \(1\),设该位为 \(i\)。
- 然后判断 \(p_i\) 是否有值,如果没有把 \(x\) 存到 \(p_i\) 中,否则将 \(x\) 与 \(p_i\) 异或然后重复上面的操作。(将 \(x\) 与 \(p_i\) 异或后 \(x\) 的最高位上的 \(1\) 就没了,至于变成了啥也无所谓了)
把所有元素都插入后,我们就得到了这组元素的线性基。
这样构造的线性基满足它该有的所有性质,\(p_i\) 数组也符合定义。
Code:
void Insert(int k) {
for(int i = Max; i >= 0; --i) { // Max 表示二进制最高位
if(!(k & (1ll << i))) continue;
if(!p[i]) { p[i] = k; return ; }
k ^= p[i];
}
}
操作
求最大值
给你一堆元素,挑几个异或起来,是他们的值最大,输出最大值。
我们先用这组元素构造出线性基。然后贪心的进行选择,选高位的肯定比低位的要更优。
所以我们从高位向低位遍历,如果异或上 \(p_i\) 更优就异或。最后的结果就是要求的最大值。
为什么能直接用?线性基的元素都是通过已知的元素异或而来,肯定是正确的。
Code:
int Query() {
int res = 0;
for(int i = Max; i >= 0; --i) res = max(res, res^p[i]);
return res;
求一个数是否能被表示出来
把这个数扔到线性基里跑一边就行。
每次挑这个数的最高位进行异或,都能把最高位消掉。
如果最后这个数为 \(0\) ,说明该数可以被表示出。
线性基合并
把一个线性基的每个元素插入另外一个线性基即可。
查找严格次大值
先找到最大值,然后从低位向高位枚举,然后找到两者都为一的异或上, 然后退出即可。
例题
下午再补先咕咕
鸣谢
标签:基中,int,res,元素,笔记,异或,线性 来源: https://www.cnblogs.com/Silymtics/p/14953835.html