线性基学习笔记
是什么
常用于处理线性无关或最大异或和或最小异或表示集(即最小能用多少个数的异或和表示出原集合中的数)等问题
线性基,是一个向量集合,是一种压缩向量集合的手段,因此可以降低复杂度。
具体而言,就是线性基里的若干向量通过线性操作表示出原集合的每一个元素,且线性基内部的向量全部线性无关
因此线性基内的向量个数仅为向量的维度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;
}
};
看都看了,顺手点个推荐呗 :)

浙公网安备 33010602011771号