其实是 \(\mathbb{F}_{2}^n\) 空间的一个线性无关向量组。
前置知识
向量
定义 \(n\) 维向量 \(v=(v_1,v_2,\dots v_n)\) 为一个 \(n\) 元有序数组,记作 \(v\in \mathbb{R}^n\),也即 \(n\) 维实数空间的一个向量。
定义如下运算:
- \(c\in \mathbb{R},v\in \mathbb{R}^n,cv=(cv_1,cv_2\dots cv_n)\),也就是每一维相乘,称为数乘。
- \(v_1,v_2\in\mathbb{R}^n,v_1+v_2=(v_{1,1}+v_{2,1},v_{1,2}+v_{2,2}\dots v_{1,n}+v_{2,n})\)
线性组合与张成空间
定义向量集 \(V=\lbrace v_1,v_2,\dots,v_n\rbrace\),若存在 \(c_1,c_2\dots c_n\in \mathbb{R}\),满足向量 \(x=\sum c_iv_i\),则称 \(x\) 是 \(V\) 为 \(c_1,c_2\dots c_n\) 为权的线性组合,所有这样的 \(x\) 组成的集合称为 \(V\) 的张成空间,记作 $$\operatorname{span}(V)$$
线性相关
对于向量集 \(V=\lbrace v_1,v_2,\dots,v_n\rbrace\),若 \(\exists j,v_j\) 可以表达为 \(v_1,v_2\dots v_{j-1}\) 的线性组合(注意取到 \(j-1\) 即可)
基
定义:若向量集 \(B\) 线性无关,则称 \(B=\operatorname{span}(B)\) 的一组基。
- \(B\) 的任意真子集不是 \(\operatorname{span}(B)\) 的基
- 对于任意 \(v\in \operatorname{span}(B)\),存在唯一的 \(c_1,c_2\dots c_n\),满足 \(v\) 是 \(B\) 以 \(c_1,c_2\dots c_n\) 为权的线性组合
- 对于任意线性有关集 \(V\),存在其真子集 \(B\) 满足 \(\operatorname{span}(B)=\operatorname{span}(V)\)
一个线性空间可能有多组基。
异或线性基
其实是 \(\mathbb{F}_2^n\) 空间的一个 \(k\) 维子空间的基(指数域是 \(2\) 的 \(n\) 维空间,算术意义上就是 \([0,2^n-1]\) 的整数)
本质:
异或是 \(\bmod 2\) 意义下的加法
将一个 \([0,2^n-1]\) 的整数的每一二进制位看作取值为 \(0/1\) 的向量 \(v_i\),那么整数就对应上了一个向量。
类似地,我们定义张成空间:
- 定义序列 \(a\) 的张成空间 \(\operatorname{span}(a)\) 为从 \(a\) 中挑选若干数字可以异或得到的数字之和,换句话说就是 \(a\) 的所有子序列(可以空)元素异或和组成的集合
线性基的构造方法
构造线性基,我们考虑用增量法来构造线性基。假如现在要插入一个向量,从左向右不断消去1,直到出现了第一个无法消去的1,说明这个向量无法用现在的几组基底表示出来,所以将其插入线性基。
代码实现
ll d[65];
void ins(ll x){for(int i=60;i>=0;i--)if((x>>i)&1){if(d[i])x^=d[i];else{d[i]=x;break;}}
}
性质:
- 序列 \(a\) 的线性基为 \(\operatorname{span}(a)\) 的一组基。
- 线性基是线性无关向量组
- 线性基里有值的元素个数所有张成空间是 \(\operatorname{span}(a)\) 的向量组里最少的。
- 设 \(B\) 为线性基,则 \(|\operatorname{span(a)}|=2^{|B|}\)
标准基,也称上三角基。
一个张成空间很可能不止一组基,而标准基寻求一种标准的表示方法。
我们将一般的线性基执行如下操作:
for(int i=60;~i;--i)if(d[i])for(int j=i-1;~j;--j)if((d[i]>>j)&1)d[i]^=d[j];
容易发现操作后的线性基同样也是原张成空间的基,且满足将该向量组写为 \(01\) 矩阵后,每一行的最高位 \(1\) 满足该列仅有这个位置是 \(1\)。
类似于阶梯型矩阵和简化阶梯型矩阵。
这相当有用。
应用
第 \(k\) 小异或和
\(k\) 从零开始。
将线性基化为标准基,设其按大小排序后是 \(d_0,d_1,\dots,d_m\),则该异或和为将 \(k\) 二进制分解后为 \(1\) 的位对应的 \(d\) 异或后的值。
读者自证不难
特别的,最大异或和就是全部异或起来,而 \(\min_{x\in \operatorname{span}(B)}x\oplus v\) 就是将 \(v\) 尝试插入线性基后剩下来的值。
线性基合并
直接暴力把一个线性基插入另一个线性基即可。
线性基求交
定义线性空间 \(V_i\) 的基底为 \(B_i\),现在我们希望求出 \(V_1\cap V_2\) 的基底 \(W\)。
-
引理:令 \(T=V_1\cap B_2\),若 \(B_1\cup(B_2/T)\) 线性无关,则 \(T\) 是所求的 \(W\) 之一。
证明:考虑反面证明,若 \(T\) 非法则线性有关,设 \(v\in V_1\cap V_2\) 且不能被 \(T\) 表出。
那么有 \(v=x\oplus y,x\in T,y\in B_2/T\),且 \(y>0\)。
因为 \(x\in T\implies x\in V_1\),同时 \(v\in V_1\),所以 \(x\oplus v=y\in V_1\)
\(y\) 就可以被 \(B_1\) 表出
则 \(B_1\cup (B_2/T)\) 线性相关。
考虑如何求出 \(W\),可以考虑枚举 \(x:1\to |B_2|\):
-
\(b_x\in B_2\)
-
\(b_x\) 可以被 \(B_1\cup \lbrace b_1,b_2\dots b_{x-1}\rbrace\) 表出
设 \(b_x=p\oplus q,p\in V_1,q\) 被 \(\lbrace b_1,b_2\dots b_{x-1}\rbrace\) 表出,则将 \(q\) 加入 \(W\)。
-
否则不做任何操作。
-
证明这样可以求出 \(W\),只需要证明 \(V_{B_2-W}\cap V_1=\lbrace 0\rbrace\) 即可。
设 \(x\in V_{B_2/W}\cap V_1,x>0\)
则有 \(x\) 可以被 \(B_1\) 以及 \(B_2/W\) 表出,那么取出 \(B_2/W\) 里下标最大的 \(b_k\),则有 \(b_k\) 可以被 \(B_2/W/\lbrace b_k\rbrace\cup B_1\) 表出,那么与假设不符。
证毕。
struct node{int d[32];node(){memset(d,0,sizeof d);}void ins(int x){for(int i=31;i>=0;--i)if((x>>i)&1){if(d[i])x^=d[i];else {d[i]=x;return ;}}}bool count(int x){for(int i=31;i>=0;--i)if((x>>i)&1){if(!d[i])return false;x^=d[i];}return true;}node operator&(const node b)const {node tmpa;memcpy(tmpa.d,d,sizeof d);node uda=tmpa,res;for(int i=0;i<32;++i)if(b.d[i]){int x=b.d[i],sur=0,tag=1;for(int j=i;j>=0;--j)if((x>>j)&1){if(tmpa.d[j])x^=tmpa.d[j],sur^=uda.d[j];else {tmpa.d[j]=x,uda.d[j]=sur,tag=0;break;}//uda.d[i] 指该元素使用的 B_1 中元素 xor 和}if(tag)res.ins(sur);}return res;}
};
带删除线性基
肯定是离线的啦
考虑求出每个元素的删除时间 \(t_i\),按加入时间顺序将元素加入线性基,插入 \((v,t)\) 时,同样依次扫描各个二进制位,执行如下操作:
若当前线性基这一位的删除时间早于 \(t\),将 \(v\) 与这一位互换(注意 \(t\) 也需要互换),并继续向下插入
否则就异或后正常插入
查询时就将时间早于当前时间的位不考虑即可。
当然可以自然扩展到前缀线性基。
考虑对于原序列的每一段前缀,维护一个前缀线性基。
对于每个二进制位,维护可以贡献它的基底中下标最大的一个。
插入的时候如果存在基底,考虑将插入的数和基底中下标较小的一个继续向下插入,另一个作为当前位的基底。
查询只需要第 \(r\) 个前缀线性基中下标大于等于 \(l\) 的基底。
线性基与无向图路径
核心:无向图可以走回头路,那么一个环的异或值可以不耗任何代价得到
对于一个无向连通图,有边权,构建 DFS 树后,将所有环的权异或组成一个线性基,具有以下性质
- 这个线性基只需要所有返祖边所对应简单环异或和即可构建(其他环可以表达为这些环的复合)
- 点 \(u→v\) 的所有可能的路径的异或值均可以用这两者的简单路径的异或值与线性基中的值表出,这是因为走到一个环又走回去是可以抵消的,这时候产生贡献的只有环。
- 对于 \(u→v\) 所有路径的异或值,用 \(B\) 表示所有返祖边构成环的权值组成的线性基,则有将 \(d_u\oplus d_v\) 加入 \(B\) 后,\(B\) 的张成空间内的所有元素在原图都能够找到一条 \(u\to v\) 的路径其异或值是这个(特判 \(0\))
相关题目
幸运数字
给定一颗树,点有点权,多次询问,给出 \((u,v)\),求树上 \(u\to v\) 路径选出任意多个点的点权异或和最大值
等价于求出 \(u\to v\) 路径上所有点的点权构成的线性基。
可以利用前缀线性基的方法做一个后缀线性基,详细的说,求出线性基 \(b_i\) 表示 \(1\to i\) 路径上所有点构成的线性基,每一位贪心保留深度较大的位。
那么每次相当于是拿出 \(b_u,b_v\) 两个线性基里深度 \(\ge dep_{lca(u,v)}\) 的元素重组一个线性基即可
复杂度 \(O(n\log n\log V)\)
P 哥的桶
相当于给定 \(n\) 个线性基,支持动态在一个线性基里插入一个值,以及询问 \([l,r]\) 的线性基合并后的最大异或和。
线段树暴力维护线性基合并即可,\(O(n\log^3 n)\)
新Nim游戏
考虑从大到小插入线性基,如果插入失败说明此数必选。
正确性:线性基上每一位尽可能让更大的数字占掉不劣。
CF1100F
相当于 P 哥桶的静态版本,每个位置只有一个数。
一个 \(\log^2\) 的做法是考虑是静态的,于是离线询问,分治计算答案,一共执行 \(O(n\log n)\) 次插入,单次 \(\log\),一共执行 \(O(q)\) 个合并,单次 \(\log ^2\)
但是更一般地我们采用前缀线性基做即可。
无力回天NOI2017
线性基不支持整体标记,所以我们需要找某些手段将区间修改变成单点修改。
不妨设 \(b_i=a_i\oplus a_{i-1}\),每次就变成了单点修改。
至于区间 \(a_l,a_{l+1}\dots,a_r\) 的线性基,等价于 \(a_l,b_{l+1},b_{l+2}\dots b_r\) 的线性基,这是显然的(线性组合)。
那么就可以线段树暴力维护 \(O(n\log ^3 n)\) 了
CF959F
线性基性质的扩展。
\(n\) 个元素构成的线性基 \(B\),其任意元素 \(x\in \operatorname{span}(B)\),\(n\) 个元素里,都恰有 \(2^{n-|B|}\) 个子序列 \(xor\) 和为 \(x\)。
证明:
我们知道,线性基每个元素是由某些元素异或得到,不妨将其也表达为一个向量(出现/不出现)
插入时,会判断 \(|B|\) 个线性基量是否选择,就会被这些线性基元素表达的向量得到一个表达集合。
考虑到有 \(n-|B|\) 个元素插入失败,他们其实相当于是提供了等效集合的可行性,每个都是选或者可以不选(选上后线性基可以再选一些让其 \(xor\) 和为零),不影响答案
所以就是 \(2^{n-|B|}\)
CF938G
相当于每条边有存在时间,考虑可撤销带权并查集维护线段树分治,维护当前情况的线性基。
每走到一个节点时,保存当前的线性基用来撤销,这部分总 \(\log^2\)
总插入复杂度是 \(\log^2 n\)
插入边时,如果不连通,那么利用带权并查集也可以求出新边边权,如果连通那么成环,将其值插入线性基。
而总查询复杂度是 \(\log\) 的。
所以总复杂度 \(\log^2\) 的。
CF388D
本质上是求有多少个本质不同的线性基满足其最大异或值不超过 \(n\)。
考虑我们只计数标准型线性基保证不重不漏。
那么设 \(f_{i,j,0/1}\) 表示 \(\ge i\) 的位已经填完,当前线性基已经在前面钦定了 \(j\) 个有值的元素,当前这一位如果再加上 \(2^i\) 能否大于 \(n\)。
将线性基元素 \(<i\) 的位的取值延迟决策是很有意义的。
有如下限制:如果当前位作为某个线性基的最高位,那么这一列仅有这个有值。
转移考虑分类讨论:
-
当前不填
基本转移:\(f_{i,j,0}·2^j\to f_{i-1,j,0}\)
-
\(n\) 该位为 \(0\)
\(f_{i,j,1}·2^{\max(0,j-1)}\to f_{i-1,j,1}\),这是已经填过的线性基全部异或起来这一位取零,所以有 \(2^{\max(0,j-1)}\) 种方法
-
\(n\) 该位为 \(1\)
\(f_{i,j,1}·2^{\max(0,j-1)}\to f_{i-1,j,0}\)
\(f_{i,j,1}·2^{\max(0,j-1)}\to f_{i-1,j,1}\)
对应一个取奇数个 \(1\),一个取偶数个 \(1\) 的 \(f\) 能否继续顶住上界。
-
-
当前要填
基本转移:\(f_{i,j,0}\to f_{i-1,j+1,0}\),这时候相当于该列全是零。
- \(n\) 该位为零,算了
- \(n\) 该位为 \(1\),有 \(f_{i,j,1}\to f_{i-1,j+1,1}\)
CF1299D
先断开所有与 \(1\) 相连的边,那么说明每个连通块至多有 \(2\) 条边与 \(1\) 相连。
注意到值域很小,本质不同的线性基只有 \(374\) 个,可以直接暴力预处理出来,并将其作为状态。
这相当于是求在所有连边方案里有多少个,拿出所有环异或值,异或不出 \(0\) 的方案数。
设 \(f_{i,j}\) 为处理完前 \(i\) 个连通块,当前线性基状态是 \(j\),预处理 \(trans_{j,k}\) 表示 \(j,k\) 两个线性基合并后如果合法的后继状态。
可以分讨:
- 该连通块内部环可以表出 \(0\),则必须全部断掉
- 只向这个连通块连一条边,仍然合法
- 向这个连通块连两条(如果存在),会产生新环,如果仍然合法,也可以加入 dp 转移。
八纵八横
注意到原图连通,因此可以先求出 dfs 树,然后将所有树上的简单环的异或值插入线性基
接着操作1,2都等价于动态加入/删除某个值
然后问最大 xor 值。
离线下来直接带删 bitset 即可。