線性基:對一組數建立線性基得到:一組數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
}