线性基学习笔记
定义
基:在线性代数中,基(也称为基底)是描述、刻画向量空间的基本工具。向量空间的基是它的一个特殊的子集,基的元素称为基向量。向量空间中任意一个元素,都可以唯一地表示成基向量的线性组合。如果基中元素个数有限,就称向量空间为有限维向量空间,将元素的个数称作向量空间的维数。
同样的,线性基是一种特殊的基,它通常会在异或运算中出现,它的意义是:通过原集合 \(S\) 的某一个最小子集 \(S_1\) 使得 \(S_1\) 内元素相互异或得到的值域与原集合 \(S\) 相互异或得到的值域相同。
简单来说,线性基就是一个有特殊性质的集合。
性质
- 线性基能相互异或得到原集合的所有相互异或得到的值。
- 线性基是满足性质 \(1\) 的最小的集合
- 线性基没有异或和为 \(0\) 的子集。
一些操作
构造
主要是枚举当前数的每一位,看当前位是否存在,如果不存在,就将当前数插入进集合,否则就继续,当当前的值变为 0 的时候,说明已经可以被其他
//s[i] 为线性基
void insert(int x)
{
for(int i=60;i>=0;i--)//枚举当前插入的数的每一位
{
if(x&(1<<i))//当 x 的这一位不为 0 的时候,才有可能做出贡献
{
if(s[i]) x^=s[i];//如果当前这一位有值了,就把这一位消掉,如果最后变为 0,说明插入失败
else//插入成功
{
s[i]=x;//当前位对应的线性基为插入的数
break;
}
}
}
}
求最大值
int query_max()
{
int Ans=0;
for(int i=60;i>=0;i--)
if(Ans^s[i]>Ans)
Ans^=s[i];
return Ans;
}
求最小值
\(s\) 里的,就是最小的 \(s_i\)
int query_min_in()
{
int Ans=INF;
for(int i=60;i>=0;i--)
if(s[i])
Ans=min(Ans,s[i]);
return Ans;
}
如果是求整个序列能异或出的最小值而不是这个序列的线性基能异或出的最小值的话,要看一看有没有元素不能插入线性基,如果有,那么最小值就是 \(0\),否则依然是最小的 \(s[i]\)。
求第 k 小
从一个序列中取任意个元素进行异或,求能异或出的所有数字中第 \(k\) 小的那个。
void init()
{//预处理的意义是提供最高位的 1
for(int i=1;i<=60;i++)
for(int j=1;j<=i;j++)//枚举当前位前的每一位
if(s[i]&(1<<(j-1))//当前位为 1 的话
s[i]^=s[j-1];//与 j-1 这个线性基异或,消去当前位(线性基下标从 0 开始)
}
int query_kth(int k)
{
if(k==0 && cnt<n) return 0;
if(cnt<n) k--;
init();
int Ans=0;
for(int i=0;i<=60;i++)
if(s[i]!=0)//提供出来的 1 与当前 k 的二进制位上的 1 对于,求出的 Ans 就是第 k 小的
{
if(k%2) Ans^=s[i];
k/=2;
}
return Ans;
}
判断一个数是否可以被线性基中的异或到
看当前数是否能插入线性基就可以了
储备好基础知识后,就可以做题了。
luoguP3265 高斯消元+线性基
还有几道题和题解,先咕了。