線性基淺談


線性基淺談

一、線性基淺談

  在了解線性基之前,要簡單理解什么是基。在線性代數中,基又稱為基地,是刻畫向量的工具。對於基底的元素我們稱為基向量,向量空間的任意一個元素都可以唯一表示成為基向量的線性組合。同樣,線性基也是一種基,它是一種特殊的基,一般用來求異或問題,所以在這里就先按照解決異或問題來講述。

  這種特殊的基是由$64$個數字或$32$個數字組成,具體是由幾個數字組成要取決於,原題中給出的數字集合在二進制下的最高位,解釋一下:若原題中的答案在$int$范圍內,則運用$32$位線性基足以,若答案在$long\ long$范圍內,就一定要用$64$線性基來解決,高精度另當別論。

  現在對於$n$個數字(下面稱這$n$個數為原數集):$a_1,a_2 ……a_n$,構建線性基,先不提線性基是如何構建出來的,先說一說線性基有什么性質:

  1.原數集中的任意一個數字都能夠通過線性基中的元素異或出來(這與線性基的構建方式有關)。

  2.原數集中的數字異或出來的值域與線性基中的元素以后出來的值域相等(通過上一條性質可知)。

  3.線性基中沒有異或和為零的非空子集:現在假設存在這樣一個子集使得$b_1,b_2……b_x$的異或和為零,那么根據異或的性質能得出:$b_1=b_2\oplus b_3\oplus……\oplus b_x$,既然$b_1$已經能用除他之外的線性基元素表示出來,我們便沒有必要再將$b_1$放在線性集中。

  4.線性基中的選取元素的每一種方案,都對應一個異或值,不存在多種選取方案對應同一個異或值的情況:現在假設存在這種情況,那么我們就會存在一個非空子集的異或值為零,這與上一條性質矛盾。

  5.線性基是滿足以上性質的最小集合,即線性基中不存在任何一個多余的元素。

二、線性基的構造

  (在下面描述中,稱線性基對應的第$i$位元素為$place_i$)對於每一個數字$num$,從高位向低位掃,掃到第$x$位為$1$時,若當前$place_x$有數字,則將$num$異或上$place_x$,即使$num=num\oplus place_x$,並向下繼續掃,若$place_x$沒有數字,則當前$num$就使$place_x$,即$place_x=num$。

  下面有兩種寫法:第一種寫法是按照上方描述的過程寫的,第二種是以上方描述的過程為思想進行改進的,是所有$n$個數字同時插入。

void insert(long long x)
{
    for(int i=63;~i;i--) if((x>>i)&1ll)
    {
        if(!place[i]) {place[i]=x;return;}
        else x^=place[i];
    }
}
void insert(int *num)
{
	for(int j=63;~j;j--)
    {
        int p=0;
        for(int i=1;(!p)&&i<=n;i++)
            if((!v[i])&&((num[i]>>j)&1ll)) p=i;
        if(!p) {place[j]=0;continue;}
        v[p]=true,place[j]=num[p];
        for(int i=1;i<=n;i++) if(i!=p&&((num[i]>>j)&1ll))
            num[i]^=num[p];
    }
}

三、線性基應用

  1.詢問數字$x$是否在當前線性基異或集合中:

  我們對於數字$x$從高位向低位掃,若數字$x$在二進制下的第$i$位為$1$,則異或上$place_i $,若數字$x$最后異或出來等於零,則數字$x$在當前線性基的異或集合中,反之則不在。

bool check(long long x)
{
    for(int i=63;~i;i--)
        if((x>>i)&1ll) x^=place[i];
	return x==0;
}

  2.將線性基$A​$和線性基$B​$合並:

  我們將線性基$A​$中的每一個數字都依次插入到線性基$B​$中即可。

struct Base
{
	long long place[N];
    void insert(long long x)
    {
        for(int i=63;~i;i--) if((x>>i)&1ll)
        {
            if(!place[i]) {place[i]=x;return;}
            else x^=place[i];
        }
    }
};
void merge(Base A,Base &B)
{
    for(int i=63;~i;i--) if(A.place[i])
        B.insert(A.place[i]);
}

  3.用線性基求當前數集能異或出來的最大數字:

  我們對於當前數集構造線性基,因為二進制下高位的$1$對於答案的貢獻要比下面所有的位數都為$1$的貢獻還要大,所以我們可以進行貪心,若答案異或上當前位數上的數字比答案要大,則異或。

long long mx()
{
    long long ans=0;
    for(int i=63;~i;i--)
        if((ans^place[i])>place)
            ans^=place[i];
    return ans;
}

  4.用線性基求當前數集能異或出來的最小數字:

  我們對於當前數集構造線性基,直接取出最后一位不是零的數字即可,為什么?仔細想想挺簡單的。

long long mn()
{
    for(int i=0;i<=63;i++)
        if(place[i]) return place[i];
    return -1;
}


免責聲明!

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



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