「线性基」学习笔记

这里指OI里的线性基,用来解决与异或相关的问题。spa

线性基是一个整数集合对应的一个集合,其异或值域与原序列彻底相同(很少很多)。所谓异或值域,就是在集合中选择任意子集的异或和的全部取值。这样一来,就异或和意义下,这两个集合就彻底等效了。code

异或的性质blog

交换律:$a \oplus b = b \oplus a$class

结合律:$a \oplus (b \oplus c) = (a \oplus b) \oplus c$二进制

自反性:$a \oplus a = 0$方法

异或能够理解为返回某两位是否不一样,或者理解为不进位的加法。集合

构造线性基di

当线性基内的元素的异或和可以表示出原集合内的每一个元素时,它们的值域就必定相同了。由于考虑原集合中若干个元素的异或和时,只须要在线性基中选出对应的子集表示原集合被选中的每一个元素而后异或起来就能够了。对于线性基内的一个元素被选屡次的状况,根据自反性能够抵消。co

假设要维护的数的二进制都是$L$位或更少的,咱们考虑在线性基中维护$L$个元素,其中第$i$个是$i$位的(保证开头是1)。这样的话,线性基内的元素必定是互不相同的。void

假设如今要往线性基里加入一个元素$x$。咱们想在线性基里加上若干元素(或不变),使得从线性基里选一个子集可以表示出$x$。根据自反性,也就是要在线性基中找出一个子集使得其与$x$的异或和为0。也就是要选出几个元素抵消$x$。既然线性基内每个的开头位都是不同的,咱们就很好判断——咱们从高到低考虑$x$的第$i$位,若是是0那么一定不能选元素$i$(因为咱们从高到低考虑,选$i$就永远没法抵消掉这一位);若是是1那么必须选元素$i$(因为咱们从高到低考虑,不选$i$就永远没法抵消掉这一位),选了$i$以后,问题转化为$x$与这个元素异或以后的值$x'$与剩余元素的异或和要是0,确定有$x>x'$,所以继续按相同的方法作就好了。若是发现某一位的线性基不存在,那么直接将其设为$x$就好了。挺自然的。

线性基内的元素一旦肯定就不会修改了。

inline void insert(int x){ for(int i = 50; i >= 0; --i){ if(x & (1ll<<i)){ if(!basis[i]){ basis[i] = x; break; } x ^= basis[i]; if(!x) break; } } }

最大值

要求一个集合里元素的最大异或和,那么先建线性基。

线性基值域的最大值怎么求?从最高位到最低位贪心。先将$ans$设为0,而后从高到低去异或线性基里的元素。若是当前位是1那确定要选,这个没问题,$ans= ans \oplus basis_i$;若是当前位是0呢?那就若是$ans \oplus basis_i > ans$则异或。由于不管如何第$i$位不能变成1,那么就先设法保证后面能更大。若是到了后面能把一位从0变成1,那确定会去作;反之若是后面没这个能力,而却经过这一步使0变成1了,那确定更优了。

值域大小

线性基中的元素各不相同,所以各子集的异或和也各不相同。答案是$2^{size}$。反证法——若是存在两个子集异或和相同,那么这两个子集异或和为0。经过结合律,咱们知道若是从这两个子集中拿出一个元素$k$,其与剩余部分的异或和相同,也就是剩余部分能表示$k$,这个元素没必要存在在线性基里。

相关文章
相关标签/搜索