线性基小记

Part 0:前置知识

线性空间是一个关于以下两个运算封闭的向量集合:

  • 向量加法 \(a+b\)
  • 标量乘法 \(k*a\)

给定一个向量集合 \(A=\{a_1,a_2,\dots,a_k\}\),若向量 \(b\) 能由 \(a_1,a_2,\dots,a_k\) 经过向量加法和标量乘法运算得出,则称向量 \(b\) 能被向量 \(a_1,a_2,\dots,a_k\) 表出\(a_1,a_2,\dots,a_k\) 能表出的所有向量构成一个线性空间,称作 \(A\)张成空间,记作 \(\operatorname{span}(A)\)\(A\) 被称作这个线性空间的生成子集

任意选出线性空间的若干个向量,如果其中存在一个向量能被其它向量表出,则称这些向量线性相关,否则称这些向量线性无关

线性无关的生成子集被称为线性空间的基底,简称。基的另一种定义是线性空间的极大线性无关子集。一个线性空间的所有基包含的向量个数都相等,这个数被称为向量空间的维数


Part 1:OI 中的线性基

在 OI 中,线性基一般用于解决与异或有关的问题。

异或可以看作 \(\bmod 2\) 意义下的向量加法。因此不难直接将原有的定义推广到异或上。

规定:记 \(k\) 为二进制位长,\(cnt\) 为线性基中基底的个数。

基的构建

从矩阵的角度理解,对于一个 \(n\times m\) 的矩阵,把每一行看作长度为 \(m\) 的行向量。将矩阵看作“系数矩阵”进行高斯消元,得到一个简化阶梯形矩阵。显然,简化阶梯形矩阵的所有非零行向量线性无关。而消元过程又不改变行向量的张成空间。于是,简化阶梯形矩阵的所有非零行向量就是该线性空间的一个基。

现在给定二进制数集合 \(V\),求 \(\operatorname{span}(V)\) 的一组解。

我们集合 \(V\) 写成一个 \(|V|\)\(k\) 列的 \(01\) 矩阵,高斯消元即可。

市面上常见的线性基写法采用增量法,逐个加入向量,若能被之前的基表出则不加入。复杂度 \(\mathcal{O}(|V|k)\)。(其实本质上一样)。

struct Linear_Base
{
	LL e[S];

	Linear_Base(){memset(e,0,sizeof(e));}
	
	void insert(LL x)
	{
		for(int i=61; i>=0; i--)
			if(x&(1LL<<i))
			{
				if(e[i])
					x^=e[i];
				else
					return e[i]=x,void();
			}
	}
}

张成空间判定问题

给出一个线性无关的二进制数集合 \(B\),询问 \(a\) 是否在 \(\operatorname{span}(B)\) 中。

\(a\in \operatorname{span}(B)\) 等价于 \(a,B\) 线性相关。类似基的构建一样将 \(a,B\) 放在一起消元即可判断。

最大子集异或值

P3812 【模板】线性基 - 洛谷

要求实现一个函数 \(\operatorname{query}(x)\),表示查询 \(x\) 与线性基的最大异或和。那么最大子集异或值就是 \(\operatorname{query}(0)\)

从高位到低位考虑基,若异或后变大,则异或。

由贪心可证明正确性。

LL query(LL x)
{
	for(int i=51; i>=0; i--)
		if((x^e[i])>x)
			x^=e[i];
	return x;
}

\(k\) 小子集异或和

若原有的集合 \(V\) 是线性无关的,则异或不到 \(0\),能得到异或值的个数是 \(2^{cnt}-1\) 。(有时允许选空集则无需考虑)。

反之,能得到 \(0\),则为 \(2^{cnt}\) 个。

特判一下 \(0\),然后重构线性基,将三角基消成对角基,即令 \(e_i\)\(0\sim i-1,i+1\sim k-1\) 都为 \(0\)。并从小到大排序记为 \(b_0,b_1,\dots,b_{cnt}\)

\(k\) 按二进制展开,若第 \(i\) 位为 \(1\),则答案异或上 \(b_i\)。证明同按位贪心。

void rebuild()
{
	int tot=0;
	for(int i=0; i<=61; i++)
	{
	    if(!e[i])
	        continue;
		for(int j=i-1; j>=0; j--)
			if(e[i]&(1LL<<j))
				e[i]^=e[j];
		tmp[tot++]=e[i];
	}
}

LL ask(LL k)
{
	if(k>=(1LL<<cnt))
		return -1;
	LL res=0;
	for(int i=cnt-1; i>=0; i--)
		if(k&(1LL<<i))
			res^=tmp[i];
	return res;
}

线性基合并

由于线性基只有 \(\mathcal{O}(k)\) 个元素,所以暴力插入即可,时间复杂度 \(\mathcal{O}(k^2)\)

例题

P3265 [JLOI2015] 装备购买

就是求一个价钱最小的极大线性无关子集。同 kruskal 一样按价钱从小到大加入,求解线性基即可。

P4301 [CQOI2013] 新Nim游戏

先手想要找到一个极大的集合,使后手面对这个集合时,无法找到一个子集满足异或和为 \(0\)。因此,这个集合一定是线性无关的 。

P3292 [SCOI2016] 幸运数字

对每个节点 \(x\) 维护 \(g_{x,i}\) 表示从 \(x\) 向上走 \(2^i\) 步所到达的所有节点(不包括 \(x\))的线性基。由于可重复贡献直接树上 RMQ 即可。

P4839 P 哥的桶

使用线段树维护线性基合并。复杂度 \(\mathcal{O}(n\log n\log ^2 V)\)

CF895C Square Subsets

套路地想到质因数分解,指数全部 \(\bmod 2\),因为 \(a_i\leq 70\),于是将每个数用它的质因子指数的二进制表示。那么成绩操作相当于异或操作,即问有多少个子集异或和为 \(0\)

构建线性基,不在线性基里的数可以自由选择,所以答案为 \(2^{n-|V|}-1\)

posted @ 2024-02-28 14:49  xishanmeigao  阅读(86)  评论(0)    收藏  举报