线性基学习笔记

是什么 

常用于处理线性无关最大异或和最小异或表示集(即最小能用多少个数的异或和表示出原集合中的数)等问题

线性基,是一个向量集合,是一种压缩向量集合的手段,因此可以降低复杂度。

具体而言,就是线性基里的若干向量通过线性操作表示出原集合的每一个元素,且线性基内部的向量全部线性无关

因此线性基内的向量个数仅为向量的维度n。

对于这个,我们从方程的角度去理解:

把每个向量看作一条方程,向量的每一维对于一个未知数

即m个n维向量,相当于m条n元方程

如果一条方程能被其他方程通过线性运算表示出来,那么它就可以被去掉。

最后的结果就是该集合的线性基

怎么做

构造线性基的过程可以类比高斯消元。

我们最终会把线性基中的向量集化为上三角式矩阵,如下图。

 

 

具体而言,每加入一个向量,我们就从上到下将该向量依次减去每一条向量,每减一次就将一个变量消掉,直到无法再消为止

这样就可以得到一个上三角矩阵了。

代码如下

vector<data> vec;
int n,m;
bool insert(data x)
{
	int p1=1,p2=1;
	while(fabs(x.arr[p1])<eps&&p1<=m) p1++;
	for(int i=0;i<vec.size();i++)
	{
		while(fabs(vec[i].arr[p2])<eps&&p2<=m) p2++;
		if(p1>p2) continue;
		if(p1<p2) break;
		double t=x.arr[p1]/vec[i].arr[p1];
		for(int j=p1;j<=m;j++)
		{
			x.arr[j]-=vec[i].arr[j]*t;
		}
		while(fabs(x.arr[p1])<eps&&p1<=m)
			p1++;
	}
	if(p1<=m)
	{
		vec.push_back(x);
		for(int j=vec.size()-1;j;j--)
		{
			int t=1;
			while(fabs(vec[j-1].arr[t])<eps) t++;
			if(p1<t) swap(vec[j],vec[j-1]);
			else break;
		}
		return true;
	}
	return false;
}

  

扩展

处理异或和的线性基是线性基中的一种

就是把每个数看作一个向量,它的每一个二进制位看作一维,这样就把每个数变成了一个31维向量,注意构造过程中要特殊化处理。

代码如下

struct linerbase
{
	int val[32];
        //最小异或表示集即为val中不为0的项
	void insert(int x)
	{
		for(int i=31;i>=0;i--)
		{
			if(((x>>i)&1)==0) continue;
			if(!val[i])
			{
				val[i]=x;
				return;
			}
			x^=val[i];
		}
	}
	linerbase()
	{
		memset(val,0,sizeof(val));
	}
        //查询最大异或和
	int query(int x)
	{
		for(int i=31;i>=0;i--)	if((x^val[i])>x) x^=val[i];
		return x;
	}
};

  

posted @ 2021-07-19 21:59  linzhuohang  阅读(204)  评论(0编辑  收藏  举报