线性基

线性代数中,我们学过极大线性无关组

极大线性无关组:在线性空间中拥有向量个数最多的线性无关向量组

换言之,任取一个子集所表示的向量不能由集合中剩余的向量表示。

在计算机语言中,我们应用在一些方面,称之为线性基。
eg.P3812 【模板】线性基

题意: 给你 n 个数字,取任意个,使它们的异或和最大。
思路:将这 n 个数字转化成 2 进制,每个数字对应一个 01 构成的向量,所有这些向量就构成了一个空间。
原题就转换为求这个向量组的极大线性无关组,也就是求向量基。
 
首先来证明一个性质:
取向量组中的两个向量 a,b,把 a,b 中的任意一个向量替换成 a xor b,替换前后向量组中的向量的线性组合得到的空间相同。简单来说,替换前后 能异或的值一样。(这就是异或的神奇之处了)。
笔者认为不难证明,感兴趣的同学可自行证明。
 
所以把向量组里的向量互相异或,极大线性无关向量组的大小是不变的
基本思想是:从左到右扫描每个向量,对于第 i 个向量的第 j 位,如果前面已经有第 j 位为 1 的向量,那么把第 i 个向量异或那个向量。
这样最后得到的向量组,不考虑 0 向量,最高位的 1 的位置是互不相同的。显然这些向量组无关。
 
于是这样构造出的极大线性无关组,也就是线性基,具有以下性质:
性质1:最高位 1 的位置互不相同。
性质2:任意一个可以用这些向量组合出的向量 x,组合方式唯一。
prove:假设 x 的组合方法不唯一,也就是说存在一个向量组可以组合出 0 向量,与线性无关矛盾。故组合方法唯一。
性质3:线性基的任意一个子集异或和不为 0。其实和性质2是一样的。
 
 从直觉上有些难以理解,但是经由理性分析是正确的。
 上代码:
#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=1e6+10;
int n,m,t,q,k;
int a[N],p[N];
void guass(){
    for(int i=1;i<=n;++i){
        for(int j=62;j>=0;--j){
            if((a[i]>>j)&1){
                if(!p[j]){ p[j]=a[i];break; }
                a[i]^=p[j];
            }
        }
    }
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;++i) cin>>a[i];
    guass();
    int ans=0;
    for(int i=62;i>=0;--i){
        ans=max(ans,ans^p[i]);
    }
    cout<<ans;
}
signed main(){
    int T=1;
    //cin>>T;
    while(T--) solve();
    return 0;
}
View Code

 


线性基的应用
人们认识事物的过程总是由浅入深,线性基的应用应该不止这样。
 
应用一:给出一个数组,询问一个数能否表示为数组中的某些数的异或和。
解法:求出线性基,从二进制高位往低位判断,如果当前这一位是1,那么就把线性基所在这一位的向量取出,即异或这个向量,否则无法组合。
 
应用二:给你一个数组,询问第 k 小异或和。(hdu 3949)
解法:首先用前面的方法得到一组线性基。然后我们可以把这组线性基再次利用相互异或空间不变的性质把它改造一下,使得它有更加优美的性质:
具体改造方法如下:
首先根据性质一得到的基最高位1的位置互不相同。记 a[i] 为线性基中最高位的1在第 i 为的 向量,可以按照 i 从大到小的顺序,用 a[i] 去异或 a[j](j>i)。
这样最终得到的向量组又多了一个优美的性质:只有 a[i] 的第 i 位是1,其他的第 i 位都是0.有了这个性质,就容易证明要求第 k 小的异或和,只要把 k 二进制拆分,第 j 位是 1 就异或第 j 个线性基中的向量。正确性是显然的...但是表达能力有限,我写不出来。
另外有一个小坑,就是0能不能被异或出来的问题。如果线性基的大小和原数组一样,0是不能被异或出来的,否则可以。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2023-06-17 20:06  青阳buleeyes  阅读(58)  评论(0编辑  收藏  举报