關於線性基的一些理解


這兩天學了學線性基,覺得這個東西還挺有意思的,想發一下博客,講一下自己的一些收獲。。

學習參考:

ljh2000:http://www.cnblogs.com/ljh2000-jump/p/5869991.html

網上的神犇:http://blog.csdn.net/qaq__qaq/article/details/53812883

 

對於一個數集$V$,它的線性基$\beta$是它的一個子集,滿足$\beta$中所有數互相異或得到的集合等價於$V$中所有數互相異或得到的集合。也就是說,$\beta$可以看成是$V$的壓縮。

 

線性基有一些性質:

1.線性基的異或集合中不存在0。也就是說,$\beta$是$V$中線性無關的極大子集。(這些概念以后再補吧。。)

2.線性基中每個元素的異或方案唯一,也就是說,線性基中不同的異或組合異或出的數都是不一樣的。這個與性質1其實是等價的。

3.線性基的二進制最高位互不相同。

4.如果線性基是滿的,它的異或集合為$[1,2^{n}-1]$。

5.線性基中元素互相異或,異或集合不變。

 

那么,我們如何維護一個線性基呢?

 

插入

插入很簡單,當我們插入一個數時,從高位到低位依次枚舉當前線性基的每個元素。

如果我們插入的數x&當前位為1,那么我們分情況討論:

如果線性基當前位沒有元素,那么把當前位賦為x,並break;否則x^線性基當前位。

那么我們可以發現,插入x的最終結局是:要么x被選入線性基中;要么x最后變成了0,說明x已經可以通過線性基中的元素異或出來了。

1 il void add(RG ll x){
2     for (RG ll i=62;i>=0;--i)
3     if (x>>i&1){
4         if (!p[i]){ p[i]=x; break; }
5         x^=p[i];
6     }
7     return;
8 }

合並線性基與插入類似,將另一個線性基暴力插入一個線性基即可。

 

查詢存在性

相當於插入的操作,如果x最后變成了0,說明x已經存在於線性基的異或集合中了。

 

查詢異或集合中最大值

從高位到低位掃描。如果當前res^p[i]能使得答案變大,那么就異或。最后得到的res就是線性基異或集合中的最大值。

1 il ll getmax(){
2     RG ll res=0;
3     for (RG ll i=62;i>=0;--i)
4     if (res<(res^p[i])) res^=p[i];
5     return res;
6 }

 

查詢異或集合中最小值

最小值就是線性基中最低位的數。

 

查詢異或集合中k小值

我們考慮改造一下線性基,使得每一位互相獨立。

如果j<i,且p[i]的第j位是1,就把p[i]^p[j]。

這樣,對於二進制的每一位i。只有p[i]這一位是1,其他的都是0。

同樣,根據性質5,這個線性基的本質也是沒有改變的。

我們查詢的時候,將k進行二進制拆分,如果第i位是1,就異或上線性基中第i個元素,最終得出的答案就是k小值(這個貪心該怎么證呢。。)

 1 il void rebuild(){
 2     for (RG ll i=62;i>=0;--i)
 3     for (RG ll j=i-1;j>=0;--j)
 4         if (p[i]>>j&1) p[i]^=p[j];
 5     for (RG ll i=0;i<=62;++i) if (p[i]) d[cnt++]=p[i];
 6     return;
 7 }
 8 
 9 il ll query_kth(RG ll k){
10     if (k>=(1LL<<cnt)) return -1; RG ll res=0;
11     for (RG ll i=62;i>=0;--i)
12     if (k>>i&1) res^=d[i];
13     return res;
14 }

 

線性基大概就是這些操作吧。。感覺自己還不是很理解其中的一些操作,不過光是記下來還是很容易的。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM