线性基总结模板

线性基


看了好多博客,,,,

线性基是一组数,是一个集合的产物,一般用来求原集合子集异或和极值的问题。

有什么作用?

通过线性基中元素xor出的数的值域与原来的数xor出数的值域相同。

但同时它这组数的大小只有原集合最大数的二进制位那麽多 (60 多位),

线性基与原集合关于异或作用一样,但是他是最简的,好像线性代数里面叫做 基。

构造

求线性基时将一个数的二进制位看成一个向量。假定原集合为 a a a 数组,线性基为 p p p 数组。

对于每个 a [ i ] a[i] a[i],按二进制从高位到低位扫,找最高位的 1,假如 a [ i ] a[i] a[i] 的第 j j j 位是最高位的 1。 p [ j ] p[j] p[j]为 0 的话,即不存在,直接插入 p [ j ] = a [ i ] p[j] = a[i] p[j]=a[i];否则将 a [ i ] a[i] a[i] ^= p [ j ] p[j] p[j],继续扫 a [ i ] a[i] a[i] 剩下的位。

其实相当于不断的将 a [ i ] a[i] a[i] 插入线性基,同时保持线性基的性质(线性无关)。

const int base = 60;	// 一般long long 也就18位,即 60 多位二进制
int a[N], p[base+3];

for(int i = 0; i < n; i++){          	// 对于每个数 a[i]
    for (int j = base; j >= 0; j--){ 	// 从高位到低位找 a[i] 最高位 1 的位置
        if(a[i] >> j & 1)				// 跳过前导 0
	        if(!p[j]){                  // 该行没数,直接填
	            p[j] = a[i];
	            break;					// 填完跳出
	        }else{
	            a[i] ^= p[j];           // 该行有数,异或之后继续看 a[i] 低位
	        }
    }
}
性质
  1. 线性基中的每个向量的二进制最高位均不同,并且,我们称二进制最高位为第 i 位的元素称为“线性基的第 i 位”。
  2. 原集合 a a a 所在线性空间中每个元素都有唯一的方案由线性基中元素异或得到。

这样我们得到的 p p p 数组是一个上三角矩阵,而且元素全都是 0, 1。
类似于这样:

10010
01001
00100
00000
00001

可以知道线性基有多少组非零向量。

进一步简化 p p p 数组可以得到很多信息。下面两种方式将 p p p 数组化为对角矩阵。

  1.  for(int i = 0; i < n; i++){          // 对于每个数 a[i]
         for (int j = base; j >= 0; j--){ // 从高位到低位找 a[i] 的第一个不为 0 的数的位置
             if(a[i] >> j == 0)
                 continue;               // 跳过前导 0
             if(!p[j]){                  // 该行没数,直接填
                 p[j] = a[i];
                 for (int k = j - 1; k >= 0; k--)    // 使第 p[j] 只有第 j 位为 1
                     if(p[k] && p[j]>>k&1)
                         p[j] ^= p[k];   // 下面的行消自己
                 for (int k = j + 1; k <= base; k++)
                     if(p[k] >> j&1)
                         p[k] ^= p[j];   // 自己消上面的行
                 break;
             }else{
                 a[i] ^= p[j];           // 该行有数
             }
         }
     }
    
  2.  for(int i = base; i >= 0; i--){
         if(!p[i])
             continue;
         for (int j = i + 1; j < base; j++){
             if(p[j]>>i&1)
                 p[j] ^= p[i];
         }
     }
    

得到对角矩阵之后可以算第 k k k 小。

// 求线性基时加上
for (int i = 0; i <= base; i++){    // 后面查询用到,存非零位
    if(p[i]){
        v.push_back(p[i]);
    }
}

ll ask(ll x){               // 查询第 k 小
    if(v.size() != n)       // 线性有关,可以异或出来 0
        x--;
    if(!x)
        return 0;           // 第一小的数是 0
    if(x >= (1LL << v.size()))  // x 超出所有能得到的值数量的范围
        return -1;
    // 能得到 0,x 已经 -1了,x 最多达到2^v.size()-1;
    // 不等得到 0,x 最多达到v.size()-1
    ll ans = 0;
    for(int i = 0; i <= base; i++){ // 将第 i 为异或起来
        if(x >> i&1){           // 第 i 位为 1
            ans ^= v[i];
        }
    }
    return ans;
}
参考

https://blog.sengxian.com/algorithms/linear-basis
https://blog.csdn.net/Cassie_zkq/article/details/95396029
https://www.cnblogs.com/vb4896/p/6149022.html
https://blog.csdn.net/qq_41286356/article/details/94839220
https://ouuan.github.io/线性基学习笔记/
https://blog.csdn.net/litble/article/details/78820648

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性可以用来判断原集合是否封闭。如果一个元素能够被线性向量线性表示,那么它就可以由原集合中的元素经过线性组合得到,即原集合是封闭的。否则,如果有一个元素不能被线性向量线性表示,那么它就无法由原集合中的元素经过线性组合得到,即原集合不是封闭的。 具体地,我们可以通过将待判断的元素与线性向量进行异或操作来判断是否能够线性表示。如果待判断元素与线性向量进行异或操作后得到零向量,则说明待判断元素可以由线性向量线性表示。如果待判断元素与线性向量进行异或操作后得到非零向量,则说明待判断元素无法由线性向量线性表示。 因此,我们可以通过判断待判断元素与线性向量进行异或操作的结果是否为零向量来判断原集合是否封闭。如果待判断元素与线性向量进行异或操作后都得到零向量,则原集合是封闭的;否则,原集合不是封闭的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [线性模板](https://blog.csdn.net/weixin_43519854/article/details/96977900)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【矩阵论】线性空间与线性变换(3)(4)](https://blog.csdn.net/kodoshinichi/article/details/108916238)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值