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