恭喜您作为幸运用户被抽中阅读这篇博客——线性基

讲讲线性基吧(说ji不说ba,文明你我他)

引入:在二维平面内,只需要用x轴、y轴的两个单位向量,就可以表示出平面内的所有向量。

就是说,任何一个二维平面的向量,都可以表示成 n*\vec{x}+m*\vec{y}。这是高中都知道的东西。(\vec{x}表示x轴的单位向量,\vec{y}表示的是y轴的单位向量。)

那就可以称(\vec{x},\vec{y})是这个二维空间的基,大概口胡一下基的意思,就是用这个基就可以表示出这个空间里面的所有值了。

现在正式开始线性基:

现在有n个数字,求它们的基,这个基 也就是可以通过基中的数字,通过 “异或” 就可以将原来的n个数字表示出来(异或总知道吧,不知道可以看这里

换句话说就是我们可以在基中选取若干的数字,把他们异或一下,就可以得到原来的这个n个数字中的某个。

再换句话说,原来的这个n个数字都可以用基中的一些数字异或得到,还有,我怎么觉得这一行字变成了深蓝色,而上面的字是深绿色???不管了,可能是错觉

说了这么多,怎么得到这个基才是最重要的。

通过异或的知识我们都知道,异或是在二进制的条件下进行的。所以我们把数字全部转化成二进制来看,就很容易理解线性基了。

比如:现在有5个数字 8 、7 、5、3、2。

转化成二进制分别是:

8:1000

7:0111

5:0101

3:0011

2:0010

关于怎么求基的事情,线性代数中给了我们方法。也就是说,下面的知识,需要掌握一些基本的线性代数的知识。现在我们把这5个数字,看成在四维座标下的5个向量,现在求它们的基(这不就变成一件轻而易举的事情了)。

先搞出一个矩阵:

\begin{bmatrix} 1& 0& 0& 0& \\ 0& 1& 1& 1& \\ 0& 1& 0& 1& \\ 0& 0& 1& 1& \\ 0& 0& 1& 0& \end{bmatrix}

然后把它用异或消成一个上三角的矩阵。前面两行不需要处理,直接从第三行开始看,第三行第二个数字1(从左往右数),需要消去,那么我们就用第三行和第二行进行一次异或,那么第三行第二个数字就变成0了,也就是:7异或5,得到2,第三行也就变成了0010。现在矩阵就是:

\begin{bmatrix} 1& 0& 0& 0& \\ 0& 1& 1& 1& \\ 0& 0& 1& 0& \\ 0& 0& 1& 1& \\ 0& 0& 1& 0& \end{bmatrix}

同样的道理,对第四行数进行相同的操作,矩阵就变成了:

\begin{bmatrix} 1& 0& 0& 0& \\ 0& 1& 1& 1& \\ 0& 0& 1& 0& \\ 0& 0& 0& 1& \\ 0& 0& 1& 0& \end{bmatrix}

最后一行,用第三行的数字进行异或,也就变成了0000,最终

\begin{bmatrix} 1& 0& 0& 0& \\ 0& 1& 1& 1& \\ 0& 0& 1& 0& \\ 0& 0& 0& 1& \\ 0& 0& 0& 0& \end{bmatrix}

最后我们得到的数字: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;
}

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章