1. 程式人生 > >線性相關/線性基

線性相關/線性基

線性基有啥用

例題:P3812 【模板】線性基

我們有些時候會遇到類似這樣的問題:給定一組數字,求異或和最大值。

我們可以用線性基來解決這個問題。

怎麼構建線性基呢

那麼我們怎麼考慮這個問題呢?

我們可以類比於向量。

在向量中,我們可以用單位向量表示某一個方向上的單位量。並且我們能用n個單位向量匯出一個$n$維的空間。

 

同理對於異或空間也是可以線性基來匯出的。

我們可以把一個長整型看成$64$維的向量,每個方向為$0$或$1$。

我們考慮一個數能匯出怎樣的一個單位向量呢?

我們發現如果是單位向量,那麼這個向量除了當前這個方向上為$1$,其餘都是$0$。

但是在這裡我們可以放寬這個要求,我們要求高位上全為$0$,這一位為$1$。

如果前$k$維的單位向量都已經被成功匯出,那麼我們就可以完全地掌控前$k$維的空間了。

 

大致就是這個意思。

我們考慮插入一個數的操作。

我們從高位(維)向低位(維)遍歷,如果我們發現當前第$i$位上為$1$,也就說明了這一個數對這個$i$維空間有影響。

我們判斷一下,當前這個空間是否已經被成功匯出了,如果已經被匯出的話,我們就有辦法消除這個影響,也就是異或上當前這個空間的單位向量。

如果沒有被成功匯出,那麼我們最高就能影響到當前這個空間了,記錄這個向量為當前空間的單位向量,結束迴圈。

有沒有插入失敗的情況呢?

有,就是當前這個向量能被完全消除影響,也就是說能被之前的向量匯出的時候。

 

線性相關

給定一個線性空間,如果一個向量存在於這個空間中,就是說這個向量和這個空間線性相關。

這個線性空間是由一個向量集合匯出的,具體見上面線性基的介紹。

例題:P3265 [JLOI2015]裝備購買

 

常用模板

下面給一些常用的模板

插入元素

1 void Insert(ll a){
2     for(int i=63;i>=0;i--)if(a&(1LL<<i)){
3         if(num[i])a^=num[i];
4         else {
5             num[i]=a;
6 return; 7 } 8 } 9 }
View Code

查詢某元素能否被表出

1 bool Inside(ll x){
2     if(!x)return 1;
3     for(int i=63;i>=0;i--)if(x&(1ll<<i)){
4         if(num[i])x^=num[i];
5         else return 0;
6         if(!x)return 1;
7     }
8     return 0;
9 }
View Code

查詢能表出的最大值

1 ll query_maxn(){
2     ll now=0;
3     for(int i=63;i>=0;i--)
4         if((now^num[i])>now)
5             now^=num[i];
6     return now;
7 }
View Code

查詢能表出的最小值

1 ll query_minn(){
2     for(int i=0;i<=63;i++)
3         if(num[i])return num[i];
4     return 0;
5 }
View Code

查詢表出的第k小值

我們要查詢第$k$小值,首先必須得讓每一個單位向量能影響的範圍獨立,也就是說當前向量的選取對其他的向量沒有影響。

之前我們保證了高位獨立,這時候我們要重新建基,建一個新基,保證高位獨立並且低位也獨立。

並且按照獨立團的個數進行重編號,那麼第k大的數就相當於重編號後的$k$所對應的二進位制數的異或和

 1 void rebuild(){
 2     for(int i=1;i<=63;i++)
 3         for(int j=i-1;j>=0;j--)
 4             if(num[i]&(1LL<<j))
 5                 num[i]^=num[j];
 6     for(int i=0;i<=63;i++)
 7         if(num[i])
 8             p[cnt++]=d[i];
 9 }
10 ll query_kth(ll k){
11     ll now=0;
12     if(k>=(1LL<<cnt))return -1;
13     for(int i=63;i>=0;i--)
14         if(k&(1LL<<i))
15             now^=p[i];
16     return now;
17 }
View Code