恭喜您作爲幸運用戶被抽中閱讀這篇博客——線性基

講講線性基吧(說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;
}

 

 

 

 

 

 

 

 

 

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