高斯消元和线性基
高斯消元
高斯消元是一种解多元一次方程的方法,但是不如约旦消元方便,所以介绍约旦消元。
约旦消元实际就是对于每个未知数钦定一个方程保留这个未知数,随后用这个方程将其他方程的这个未知数消去。
这里着重介绍无解与多解情况
首先无解优先于多解。
如果对于某一行,出现 \(0x=0\) 那便多解,若是出现 \(0x=y\) 的情况,那便无解。
在消元过程中,若是这一行多解,那在下面找方程时这一行也要算上。
若是有一行的未知数没消没,那也是无解。
线性基
这里只说异或线性基,线性空间的不多说。
异或线性基,是若干数与它们异或出来的数的基底,设值域为 \(V\) 那只需要 \(log V\) 量级的线性基即可。
设线性基为 \(p\),那么 \(p[i]\) 便是表示第 \(i\) 位为 \(1\) 且是 \(1\) 的最高位的一个元素,显然这些元素线性无关。
线性基插入
对于插入的元素,我们从最高位到最低位依次考虑,对于第 \(i\) 位,若线性基内没有,将该值加入。否则异或上该值接着往下,到最后跳出。
首先最后的加值保证了该数能被这个线性基表示出来,且保证了线性无关。所以可以这样做。
那怎么保证取线性基内若干数所异或出来的数可以由原序列若干个数异或出来呢?
对于线性基内一个数,考虑添加它时加入的序列中的数是哪个,显然这个数可分解为那个序列数与若干线性基中的别的数异或得到,再分别考虑那若干线性基的数,显然它们和这个数一样,也可分解,这样一直分解下去,最后可由若干序列数异或得到这个数,得证。
void ins(ll x){
for(int i=62;i>=0;i--)
if(x&pe(i)){
if(!p[i]){p[i]=x;sz++;return;}
x^=p[i];
}
}
求最大值
从最高位开始考虑,对于 \(p[i]\) 后面的线性基中的数的第 \(i\) 位都不为 \(1\),那么这个位置如果有值且目前答案第 \(i\) 位为 \(0\),那显然异或上这个值答案更大,就异或上然后接着考虑。
求最小值
若原序列异或不出 \(0\),那答案就是最小的 \(p[i]\),因为若其他数异或它,必定使它高位一个位置由 \(0\) 变一。
若有数未加入线性基,就说明它能通过前面序列中的数异或出来,那么这个序列就能异或出 \(0\)。
求第 \(k\) 小
考虑线性基中第 \(i\) 个有值的数,答案异或上它与不异或它所得到的数的它所代表的位置的值显然不同,这样可能答案个数就被分为相同两部分,这与 \(k\) 的第 \(i\) 位值为 \(1\) 或 \(0\) 刚好对应。
因此,我们先把 \(0\) 判掉,接着从最低位开始考虑,若 \(p[i]\) 有值,就看k最低位是否为 \(1\),如果是答案就异或上 \(p[i]\)。最后让 \(k\) 右移 \(1\)。
ll kth(ll k){
if(k==1&&sz<n) return 0;
if(sz<n) k--;
if(k>=pe(sz))return -1;
ll ans=0;
for(int i=0;i<=60;i++){
if(p[i]){
if(k&1) ans^=p[i];
k>>=1;
}
}
return ans;
}
线性基求并
将一个线性基的每个数加入另一个线性基即可。

浙公网安备 33010602011771号