线性基简单学习笔记
线性基
- 百度百科【IN】
百度的第一句话似乎有点怪异
其实,对于广义的线性基,也就是线性代数里面的基。一个基也相当于该空间内的一个集合。
其实一个基的最大的特点就是:
- 它可以线性表出所有该空间里的向量(元素)
- 它的大小是最小的(也就是基中的元素个数不多)
- 且它的任何一个非空子集不会线性表出空集。
对于线性表出的意思,可以简单的理解为一些元素通过一种运算可以得到另一个元素,就称这些元素线性表出了另一个元素(线性表示出的意思)
关于第三点,可以简单证明一下,用反证法:
假如,对于,那么我们将左边的一个元素移动到右边,则变成了,那么这个元素就可以被线性表出了,所以将删除,剩下的才是线性基。
这里,我们只讲在异或意义下的线性基,也就是。
除了对于数在二进制下的异或,我们可以将其推广到集合上,也就变成了对称差,那么可以用同样的方式对于一系列集合求其线性基。
一些定义:
- 异或和
这里我们的异或和不是,而是,也就是所有的异或起来。其中为无符号的整数类型。
- 线性相关
学过线性代数的人应该知道吧QAQ
对于一个集合和集合中的任意一个元素,这个可以由集合中的其它元素线性表出,那么就称集合线性相关,反之就如果所有的都不满足该性质,就称为线性无关。
- 张成
对于一个集合的张成,我们简记为,其中:
用文字来说,就是对于每一个的子集的线性运算结果所组成的集合称作这个集合的张成。
一个结论就是对于一个线性相关的集合,去除其中任意一个元素,它的张成不变(因为这个去除的元素可以由其他的表出),这个也可以来证明最开始的特点3。
这里我们来定义线性基:
线性基
我们称一个集合(基)为的线性基,当且仅当:
- 是线性无关的(如果线性相关的话,我们可以将一些可以表出的元素删除,因为要保证最小,所以必须线性无关)
- ,也就是这个集合可以由线性表出(为的张成子集)。
- 性质
- 是最小的满足条件的集合,它的任何真子集都不可能是新的线性基,因为少了任何一个元素,那么由于线性无关,这个元素就不能被剩下的表出了,那么就不符合条件2。
- 中的任意元素都可以被线性表出。(其实也就是条件2)
构造
我们这里只讲在异或的运算下如何快速构造:
对于一个无符号(非负数)整数集,我们令它的元素最大二进制位的个数为,我们可以发现,只需对于每一位存储一个元素,那么就可以表出所有的了,所以我们可以构造一个大小的线性基。
构造方式为将每个元素插入线性基,那么复杂度就为
所以我们令为其线性基,那么可以安照如下方式构造:
- 从高位到低位扫描:
- 当时且第位为,那么我们令,然后即可停止扫描,因为到插入为止,只有能表出第位的。
- 当时,由于这一位已经可以表出了,所以我们将异或上这一位的值,继续扫描(因为要保证可以表出每一位且线性无关)。
那么构造方式就是这样,代码实现非常简单,如下:
void insert(int si){
for(int i=maxbit;i>=0;i--){
if(!(si>>i)&1) continue;
if(!X[i]){X[i]=si;return;}
si^=X[i];
}
}
对于合并两个线性基,就是将一个线性基中的元素插入另一个,复杂度为
应用
- 给出你一个集合,和一个数字,让你求最大:其实这个就扫一遍即可,不用线性基。
- 给出你一个集合,和一个数字,让你判断这个集合能否表出(异或出):先求出线性基,我们就从二进制高位到低位扫描,如果第位为,那么就将,如果最终则表示可以(也就是看能否插入线性基,如果不能插入则就可以表示出来,根据线性基的定义即可知道)。
- 给你一个集合,求出这个集合能够异或出的最大值:我们求出的线性基,然后扫一遍,每次取即为答案。
End
若有错,请及时提出联系博主
萌新才学QWQ
洛谷模板IN
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=65;
ll rec[M],a,ans;
void insert(ll a){
for(int i=61;i>=0;i--){
if(!(a>>i)&1) continue;
if(!rec[i]){rec[i]=a;return;}
a^=rec[i];
}
}
ll getmax(){
for(int i=61;i>=0;i--)ans=max(ans,ans^rec[i]);
printf("%lld\n",ans);
}
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a),insert(a);
getmax();
return 0;
}
参考学习博客: