本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!
1、線性基:
若干數的線性基是一組數$a_1 , a_2 ,... a_n $,其中$a_x$的最高位的$1$在第$x$位。
通過線性基中元素$xor$出的數的值域與原來的數$xor$出數的值域相同。
2、線性基的構造法:
對每一個數$p$從高位到低位掃,掃到第$x$位為$1$時,若$a_x$不存在,則$a_x=p$並結束此數的掃描,否則令$p=p$ $xor $ $ a_x。$
3、查詢:
用線性基求這組數$xor$出的最大值:從高往低掃$a_x$,若異或上$a_x$使答案變大,則異或。
4、判斷:
用線性基求一個數能否被$xor$出:從高到低,對該數每個是$1$的位置$x$,將這個數異或上$a_x$(注意異或后這個數為1的位置和原數就不一樣了),若最終變為$0$,則可被異或出。當然需要特判$0$(在構造過程中看是否有p變為0即可)。例子:$(11111,10001)$的線性基是$a_5=11111$,$a_4=01110$,要判斷$11111$能否被$xor$出,$11111$ $xor$ $a_5$$=0$,則這個數后來就沒有是$1$的位置了,最終得到結果為$0$,說明$11111$能被$xor$出。
個人談一談對線性基的理解:
很多情況下,只要有關異或運算和求最值,就可以用到線性基。線性基有很多很好的性質,比如說如果有很多個數,我們可以構出這些數的線性基,那么這個線性基可以通過互相$xor$,能夠構出原來的數可以相互$xor$構出的所有的數。所以可以大大減少判斷的時間和次數。同時線性基的任何一個非空子集都不會使得其$xor$和為0,證明也很簡單,反證法就可以說明。這個性質在很多題目中可以保證算法合法性,比如:$BZOJ2460$。
構造的方法有點像貪心,從大到小保證高位更大。也比較好理解。就是這幾行代碼:
for(int i=1;i<=n;i++) { for(int j=62;j>=0;j--) { if(!(a[i]>>j)) continue;//對線性基的這一位沒有貢獻 if(!p[j]) { p[j]=a[i]; break; }//選入線性基中 a[i]^=p[j]; } }
可以把$n$個數變成只有最大的數的二進制位數那么多個數,這就是線性基的優秀之處。
查詢的話,也是一個貪心思想,如果可以使得$ans$更大,就把這一位的基$xor$進$ans$。
1 for(int i=62;i>=0;i--) if((ans^p[i])>ans) ans=ans^p[i];//從線性基中得到最大值
這就是線性基的基本用法和個人的一些理解。
下面看一些練習(例題):
1、BZOJ2460
Description
相傳,在遠古時期,位於西方大陸的 Magic Land 上,人們已經掌握了用魔法礦石煉制法杖的技術。那時人們就認識到,一個法杖的法力取決於使用的礦石。
一般地,礦石越多則法力越強,但物極必反:有時,人們為了獲取更強的法力而使用了很多礦石,卻在煉制過程中發現魔法礦石全部消失了,從而無法煉制出法杖,這個現象被稱為“魔法抵消” 。特別地,如果在煉制過程中使用超過一塊同一種礦石,那么一定會發生“魔法抵消”。
后來,隨着人們認知水平的提高,這個現象得到了很好的解釋。經過了大量的實驗后,著名法師 Dmitri 發現:如果給現在發現的每一種礦石進行合理的編號(編號為正整數,稱為該礦石的元素序號),那么,一個礦石組合會產生“魔法抵消”當且僅當存在一個非空子集,那些礦石的元素序號按位異或起來為零。 (如果你不清楚什么是異或,請參見下一頁的名詞解釋。 )例如,使用兩個同樣的礦石必將發生“魔法抵消”,因為這兩種礦石的元素序號相同,異或起來為零。
並且人們有了測定魔力的有效途徑,已經知道了:合成出來的法杖的魔力等於每一種礦石的法力之和。人們已經測定了現今發現的所有礦石的法力值,並且通過實驗推算出每一種礦石的元素序號。
現在,給定你以上的礦石信息,請你來計算一下當時可以煉制出的法杖最多有多大的魔力。
正解:貪心+線性基
解題報告:
顯然這道題可以用線性基來維護一個我們選取的非空子集中不存在異或出$0$的情況,但是我們還需要得到的權值最大,那么直接對於每件物品按權值排序,按權值從大到小插入到線性基中就可以保證得到的線性基中的元素是權值之和最大的。
2、BZOJ2115
Description
正解:線性基
解題報告:
這道題要求從1到n的最大xor和路徑,存在重邊,允許經過重復點、重復邊。那么 在圖上作圖嘗試之后就會發現,路徑一定是由許多的環和一條從1到n的路徑組成。容易發現,來回走是沒有任何意義的,因為來回走意味着抵消。考慮這道題求得是路徑xor和最大,所以必然我們要想辦法處理環的情況。我的做法是任意地先找出一條從1到n的路徑,把這條路徑上的xor和作為ans初值(先不管為什么可行),然后我們的任務就變成了求若干個環與這個ans初值所能組合成的xor最大值。顯然,我們需要預處理出圖上所有的環,並處理出所有環的環上xor值,這當然是dfs尋找,到n的路徑的時候順便求一下就可以了。
當我們得到了若干個環的xor值之后,因為是要求xor最大值,我們就可以構出這所有xor值的線性基。構出之后,再用ans在線性基上取max就可以了。
現在我們來討論上述做法的可行性。
第一種情況:我們對最終答案產生貢獻的某個環離1到n的主路徑很遠,這樣的話,因為至少可以保證1可以到達這個環,那么我們可以走到這個環之后繞環一周之后原路返回,這樣從1走到環的路上這一段被重復經過所以無效,但是環上的xor值被我們得到了,所以我們並不關心這個環和主路徑的關系,我們只關心環的權值。
第二種情況:我們任意選取的到n的路徑是否能保證最優性。假設存在一條更優的路徑從1到n,那么這條路徑與我們原來的路徑構成了一個環,也就會被納入線性基中,也會被計算貢獻,假如這個環會被經過,那么最后的情況相當於是走了兩遍原來選取的路徑,抵消之后走了一次這個最優路徑,所以我們無論選取的是哪條路徑作為ans初值,都可以通過與更優情況構成環,然后得到一樣的結果。這一證明可以拓展到路徑上的任意點的路徑選取。
這樣我們就可以完美解決了。我第一次WA了一發,因為我沒有考慮到ans初值不為0,在線性基上取到xor的max的時候,不能單純以ans這一位是否為0來決定是否異或上基的這一位,必須要看異或之后取一個max做一個判斷才行。
直接鏈接到我的那篇博客過去辣