這是乙個看起來很像gauss-jordan消元法裡面的形式(行最簡形矩陣)的線性基,和其他人的gauss消元法裡面的形式(上三角形矩陣)看起來並不一樣。
d[i] 表示掌管二進位制第i位(1ll<= 0; --i)
++n;
d[i] = x;
for(int j = 0; j < i; ++j)
for(int j = i + 1; j < len; ++j)
return true;}}
z = 1;
return false;
}bool query(ll x)
return false;}}
return x == 0;
}// maximal
ll max()
// minimal
ll min()
}ll kthmin(ll k)
}return k ? -1 : res;
}ll size()
void show(int sl = len)
}printf("\n");
}} lb;n:線性基中非零值有多少個
z:是否可以組成0
設值域為 \(a\) 。
嘗試往線性基中插入乙個x:
問題就是x是否能被當前的線性基中的數字線性表示。
所以對於x的每個非0的位,都去找對應的d[i]和他異或,注意這樣可能會引入新的位,所以規定從高到低異或就可以每次消去一位。當其可以被線性基中的數字表示時,那麼再加上這個數本身就可以表示0了,就置z標記為1。否則要把這個剩餘的數字插入到對應的d[i]中,然後用比它低位的d[j]消去d[i]中帶有d[j]的位,再用d[i]消去比它高位的d[j]中的帶有d[i]的位。(注意順序,要先確保比i低的被掌管的位已經被消為0)。
最大值:
當不存在非零值時,判斷是否可以組成0,若0都沒有,那麼就是空集。否則,由於是行最簡形,所以就所有的d[i]都異或起來。
最小值:
當不存在非零值時,判斷是否可以組成0,若0都沒有,那麼就是空集。判斷是否能夠組成0,有0就是0,否則輸出最小的那個基底。
第k小值:
判斷是否能夠組成0,有0的話0就是最小值,--k。然後在非零的裡面找第k小的。
然後從最小的基底開始往高位掃,每次k的最低位是奇數,就選中最小的基底,否則就不選。若最後k沒有被消除完,則說明非0的值不足k個。
合併:(改變d[i]的定義後)把規模小的那個線性基插入到大的那個,或者都直接暴力掃一遍。
insert x=41
n=1 z=0
d[05]=000000101001
insert x=35
n=2 z=0
d[05]=000000100011
d[03]=000000001010
insert x=190
n=3 z=0
d[07]=000010010111
d[05]=000000100011
d[03]=000000001010
insert x=1924
n=4 z=0
d[10]=011100010011
d[07]=000010010111
d[05]=000000100011
d[03]=000000001010
insert x=737
n=5 z=0
d[10]=010101000110
d[09]=001001010101
d[07]=000010010111
d[05]=000000100011
d[03]=000000001010
insert x=1388
n=6 z=0
d[10]=010101000101
d[09]=001001010101
d[07]=000010010100
d[05]=000000100000
d[03]=000000001001
d[01]=000000000011
insert x=1238
n=7 z=0
d[10]=010001000001
d[09]=001001010101
d[08]=000100000100
d[07]=000010010100
d[05]=000000100000
d[03]=000000001001
d[01]=000000000011
insert x=686
n=8 z=0
d[10]=010000000100
d[09]=001000010000
d[08]=000100000100
d[07]=000010010100
d[06]=000001000101
d[05]=000000100000
d[03]=000000001001
d[01]=000000000011
好好用哦。
提供乙個用vector的實現:
struct lb
bool insert(ll x)
z = 1;
return false;
}bool query(ll x)
// maximal
ll max()
// minimal
ll min()
ll kthmin(ll k)
return k ? -1 : res;
}ll size()
void show(int sl = len)
printf("\n");
}} lb;
合併線性基的時候記得順便把z標記也合併。
當可以離線查詢時,可以維護[i,r]的所有線性基,當++r時從右往左掃瞄所有「當前字尾線性基」並嘗試插入,因為每個線性基最多被插入成功log次,當插入失敗時說明這個位置的值可以替代當前r的值,更前面的也會插入失敗。
struct lb
void insert(ll x, int xpos) else
x ^= d[i];}}
}}
// maximal
ll max()
} lb;
模板 數學 線性基
includeusing namespace std define ll long long const int mn 60 ll a mn tmp mn bool flag 該線性基能否表示0 嘗試向線性基中插入乙個值 void ins ll x else x a i flag true 判斷該線...
模板 線性基
難度較大,請勿棄療 給定n個整數 數字可能重複 求在這些數中選取任意個,使得他們的異或和最大。n 50sample input33 21sample output 3看上去莫名其妙地想貪心。給些定義 s 為無符號整數集 即s n 記為 xor sum s x or s um s s1 s2 s s ...
模板 線性基
給定n個整數 數字可能重複 求在這些數中選取任意個,使得他們的異或和最大。線性基模板可解決 將n個整數看做集合a 線性基即為集合a的子集 線性基中每個元素的異或方案唯一,也就是說,線性基中不同的異或組合異或出的數都是不一樣的。線性基的二進位制最高位互不相同。這樣我們先構造出線性基 然後貪心的去搞最大...