讲讲线性基吧(说ji不说ba,文明你我他)
引入:在二维平面内,只需要用x轴、y轴的两个单位向量,就可以表示出平面内的所有向量。
就是说,任何一个二维平面的向量,都可以表示成 。这是高中都知道的东西。(表示x轴的单位向量,表示的是y轴的单位向量。)
那就可以称()是这个二维空间的基,大概口胡一下基的意思,就是用这个基就可以表示出这个空间里面的所有值了。
现在正式开始线性基:
现在有n个数字,求它们的基,这个基 也就是可以通过基中的数字,通过 “异或” 就可以将原来的n个数字表示出来(异或总知道吧,不知道可以看这里)。
换句话说就是我们可以在基中选取若干的数字,把他们异或一下,就可以得到原来的这个n个数字中的某个。
再换句话说,原来的这个n个数字都可以用基中的一些数字异或得到,还有,我怎么觉得这一行字变成了深蓝色,而上面的字是深绿色???不管了,可能是错觉。
说了这么多,怎么得到这个基才是最重要的。
通过异或的知识我们都知道,异或是在二进制的条件下进行的。所以我们把数字全部转化成二进制来看,就很容易理解线性基了。
比如:现在有5个数字 8 、7 、5、3、2。
转化成二进制分别是:
8:1000
7:0111
5:0101
3:0011
2:0010
关于怎么求基的事情,线性代数中给了我们方法。也就是说,下面的知识,需要掌握一些基本的线性代数的知识。现在我们把这5个数字,看成在四维座标下的5个向量,现在求它们的基(这不就变成一件轻而易举的事情了)。
先搞出一个矩阵:
然后把它用异或消成一个上三角的矩阵。前面两行不需要处理,直接从第三行开始看,第三行第二个数字1(从左往右数),需要消去,那么我们就用第三行和第二行进行一次异或,那么第三行第二个数字就变成0了,也就是:7异或5,得到2,第三行也就变成了0010。现在矩阵就是:
同样的道理,对第四行数进行相同的操作,矩阵就变成了:
最后一行,用第三行的数字进行异或,也就变成了0000,最终
最后我们得到的数字:8,7,2,1,也就是8、7、5、3、2的基。试一试,是不是这5个数都可以由这基中的数字直接,或者若干个数字异或得到。差点忘记说了,由这5个数异或可以得到的数,线性基也一异或得到。比如这里我们就可以通过异或得到:4。所以可以把基看成是对原数据的一种压缩。
还有一些线性基的性质没有说,线性基中的数字不管怎么异或,都不会得到0,这和线性基的基性质是有关的,也就是说,用线性基中的数字去异或得到某个数字,这些数字只有一种组成。
线性基的一些普通操作:1.判断一个数能否由已知的n个数得到??直接把这个数插入这n个数的线性基,判断最后是否成功插入不就是了。
2.n个数异或的第k大或者第k小???就是把k分成二进制就是了,(还要再对这个矩阵消去右上角那些1,这个完整过程叫做高斯消元),我觉得一般来说就算不知道,都可推断出来。
3.还有一些其他很简单的、稍微一思考就能想到的问题就不说了。
4.前缀线性基,以后再写了。
注:代码中的插入,其实就是在实现消元的过程。细节的地方,懂了代码就可以领悟了。
最后,代码:
#include<bits/stdc++.h>
using namespace std;
long long int line_base[63];
bool Insert(long long int x)
{
for(int i=62;i>=0;--i)
{
if(x&(1LL<<i))
{
if(!line_base[i])
{
line_base[i]=x;break;
}
x^=line_base[i];
}
}
return x>0;
}
int main()
{
int n;
long long int a;
cin>>n;
for(int i=0;i<n;++i)
{
cin>>a;
Insert(a);
}
for(int i=0;i<10;++i)
{
cout<<line_base[i]<<endl;
}
return 0;
}