線性基(求抑或最值)

線性基:對一組數建立線性基得到:一組數a1,a2、、、an,其中ax最高位的1在第x位。

線性基作用:線性基的子集的抑或和的 值域與原數抑或和的值域相同。

性質1:線性基的任意子集的抑或和都不爲0

構造線性基:

對原數組的每一個數p,從高位到低位掃描,找到第一位爲1的,若該位上的線性基ai不存在,則ai=p,否則p=p^ai,繼續掃描下一位。

像如果原數是2,3,則插入線性基中的是1,2 

ll b[63], nb[63], tot=0,flag=false; //b爲線性基  nb用來求第K小異或值,基線性基中數 tot爲nb元素個數,flag爲true表示線性基外有數

void insert(ll  x)
 { //插入
    for(int i = 62; i >= 0; i--) 
    {
        if(x & (1ll << i)) 
        {
            if(!b[i])
            {
                b[i] = x;
                return;
            }
            x ^= b[i];
        }
    }
    flag = true;
}

查詢xor最大、小值:

ll Max(ll x) 
{  //求最大值
    ll res = x;
    for(int i = 62; i >= 0; i--) 
         res = max(res, res ^ b[i]);
    return res;
}

ll Min(ll x) 
{  //求最小值
    ll res = x;
    for(int i = 0; i <= 62; i++) 
        if(b[i])
            res ^= b[i];
    return res;
}

驗證一個數x能否被xor出

bool fin(ll x) 
{ //驗證存在性
    if(x == 0 && b[0])
        return 1;
    for(int i = 62; i >= 1; i--) 
    {
        int j = i - 1;
        if(x & (1 << j)) 
        {
            x ^= b[i];
            if(!x)
                return 1;
        }
    }
    return 0;
}

求抑或第k大

把k二進制拆分,如果k的第i位上是1,ans^=b[i]

ll Rebuild() {  //第K大
    for(int i = 62; i >= 0; i--) 
    {
         if(b[i] == 0)
             continue;
         for(int j = i - 1; j >= 0; j--) 
         {
             if(b[j] == 0)
                continue;
             if(b[i] & (1ll << j))
                b[i] ^= b[j];
         }
     }
     for(int i = 0; i <= 62; i++) 
     {
         if(b[i])
            nb[tot++] = b[i];
     }
}

ll Kth_Max(ll k) {
    if(flag)
         k--; 
    ll res = 0;
    if(k == 0)
        return 0;
    if(k >= (1ll << tot))
        return -1;
    for(int i = 62; i >= 0; i--) 
    {
        if(k & (1ll << i))
             res ^= nb[i];
    }
    return res
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章