線性基學習筆記
定義
基:在線性代數中,基(也稱為基底)是描述、刻畫向量空間的基本工具。向量空間的基是它的一個特殊的子集,基的元素稱為基向量。向量空間中任意一個元素,都可以唯一地表示成基向量的線性組合。如果基中元素個數有限,就稱向量空間為有限維向量空間,將元素的個數稱作向量空間的維數。
同樣的,線性基是一種特殊的基,它通常會在異或運算中出現,它的意義是:通過原集合 \(S\) 的某一個最小子集 \(S_1\) 使得 \(S_1\) 內元素相互異或得到的值域與原集合 \(S\) 相互異或得到的值域相同。
簡單來說,線性基就是一個有特殊性質的集合。
性質
- 線性基能相互異或得到原集合的所有相互異或得到的值。
- 線性基是滿足性質 \(1\) 的最小的集合
- 線性基沒有異或和為 \(0\) 的子集。
一些操作
構造
主要是枚舉當前數的每一位,看當前位是否存在,如果不存在,就將當前數插入進集合,否則就繼續,當當前的值變為 0 的時候,說明已經可以被其他
//s[i] 為線性基
void insert(int x)
{
for(int i=60;i>=0;i--)//枚舉當前插入的數的每一位
{
if(x&(1<<i))//當 x 的這一位不為 0 的時候,才有可能做出貢獻
{
if(s[i]) x^=s[i];//如果當前這一位有值了,就把這一位消掉,如果最后變為 0,說明插入失敗
else//插入成功
{
s[i]=x;//當前位對應的線性基為插入的數
break;
}
}
}
}
求最大值
int query_max()
{
int Ans=0;
for(int i=60;i>=0;i--)
if(Ans^s[i]>Ans)
Ans^=s[i];
return Ans;
}
求最小值
\(s\) 里的,就是最小的 \(s_i\)
int query_min_in()
{
int Ans=INF;
for(int i=60;i>=0;i--)
if(s[i])
Ans=min(Ans,s[i]);
return Ans;
}
如果是求整個序列能異或出的最小值而不是這個序列的線性基能異或出的最小值的話,要看一看有沒有元素不能插入線性基,如果有,那么最小值就是 \(0\),否則依然是最小的 \(s[i]\)。
求第 k 小
從一個序列中取任意個元素進行異或,求能異或出的所有數字中第 \(k\) 小的那個。
void init()
{//預處理的意義是提供最高位的 1
for(int i=1;i<=60;i++)
for(int j=1;j<=i;j++)//枚舉當前位前的每一位
if(s[i]&(1<<(j-1))//當前位為 1 的話
s[i]^=s[j-1];//與 j-1 這個線性基異或,消去當前位(線性基下標從 0 開始)
}
int query_kth(int k)
{
if(k==0 && cnt<n) return 0;
if(cnt<n) k--;
init();
int Ans=0;
for(int i=0;i<=60;i++)
if(s[i]!=0)//提供出來的 1 與當前 k 的二進制位上的 1 對於,求出的 Ans 就是第 k 小的
{
if(k%2) Ans^=s[i];
k/=2;
}
return Ans;
}
判斷一個數是否可以被線性基中的異或到
看當前數是否能插入線性基就可以了
儲備好基礎知識后,就可以做題了。
luoguP3265 高斯消元+線性基
還有幾道題和題解,先咕了。