• 线性基学习笔记


    一堆参考资料

    https://blog.sengxian.com/algorithms/linear-basis

    https://oi.men.ci/linear-basis-notes/

    线性基这玩意儿是用来解决异或问题一类手段

    尽量说的通俗易懂一点好了

    以下指的都是异或意义下的线性基,严谨的请看参考文献的第一个

    概念

    1.异或和

      一堆数字$a_1,a_2,a_3...a_n$的异或和为$a_1xora_2xora_3...xora_n$

    2.线性相关

      若有一组数$a_1,a_2,a_3...a_n$,且存在某一个数是其他数的异或和,则称这一组数为线性相关,否则称其为线性无关

      更形象的说,如果存在某一个数能被其他数异或得到,那么这一组数就是线性相关

      比如说,$1,2,3$是线性相关,因为$1xor2=3$,但$1,2,4$是线性无关,因为不存在一个数能被其他数异或得到

    3.张成

      一组数能够异或得到的所有数,成为这一组数的张成,记做$span(S)$(其中$S$是原数的集合)

      比方说,集合${1,2,4}$的张成是${1,2,3,4,5,6,7}$

    4.线性基

      设$B$是$S$的的线性基,则$S$满足两个条件

        ①$Bin span(S)$,即$B$是$S$的张成的子集,更通俗的讲,就是$B$中的每一个数字都能被$S$中的数异或得到

        ②$B$是线性无关的

      然后线性基具有以下两个性质

        ①$S$能被$B$张成,也就是说$S$中的每一个数都能被$B$中的数表示出来

        ②$B$是$S$的极小生成集,也就是说只有$B$可以张成$S$,而$B$的任何真子集都不可以

        ③$S$中没有其他的线性无关集包含$B$作为真子集

    构造

      将每一个数$p$从高位到低位扫(二进制意义下),如果第$i$位为$1$,若$a_i=0$,则令$a_i=p$并退出,否则令$p=p xor a$

      代码如下

    1 inline void insert(ll x){
    2     for(int i=63;i>=0;--i)//逆序枚举二进制位 
    3     if(x>>i&1){//判断该位是否为1 
    4         if(!b[i]) return (void)(b[i]=x);//如果b[i]为0,则令b[i]=x 
    5         x^=b[i];//否则x=x xor b[i] 
    6     }
    7 }

      至于原因我就不说了(才不是因为我也不知道呢)

      不过需要注意的一点是,线性基的存储方式是矩阵,如果按上面的方法是把这个矩阵消成上三角矩阵,有的题目需要把它消成对角矩阵,到时候再说吧

      说人话的话,就是有的题目里这个板子不是这样写(很少),到时候再说好了

    最大值

      要求一些数字能得到的最大异或和是多少

      可以考虑贪心,从高到低枚举每一位代表的线性基,如果异或上该位的线性基后答案增大,则异或

    1 inline ll calc(){
    2     ll ans=0;
    3     for(int i=63;i>=0;--i)
    4     if(ans^b[i]>ans) ans=ans^b[i];
    5     return ans;
    6 }

    查询

      在线性基中可以查询一个数能否被异或得到

      具体的过程和插入类似,判断到了最后$x$是否变为0即可

    1 inline bool find(ll x){
    2     for(int i=63;i>=0;--i)
    3     if(x>>i&1){
    4         if(!b[i]) break;
    5         x^=b[i];
    6     }
    7     return x!=0;
    8 }

    第$K$大

      线性基可用于判断一组数字异或得到的第$K$大是多少

      设$cnt$为线性基内数的个数(也就是$b[i]!=0$的$i$的个数),那么所有能表示出的数字共有$2^{cnt}$个(包括0)

      将$K$二进制拆分,如果$K$的第$i$位为1,则令$ans^=b[i]$

      注意了,这里得把矩阵给消成对角矩阵,也就是说板子要改一改,这个放到代码里说

      消成对角矩阵有一个好处,就是每一位上的1最多只会出现一次

      还有一个需要注意的地方,如果线性基里元素的个数等于原来元素的个数,那么说明这一组元素是线性无关的,那么他们无论怎么异或也得不到0。而我们之前的求法是默认能取到0的,所以这种时候得$++K$才行

      这里是板子线性基求第$K$大

    后记

      然后简单的说一下有关线性基的应用之类的

      一般关于异或的题目都是要用到线性基的

      还有一些不是很明显的,比如有几个操作,两个操作一起搞相当于他们的异或。比如关灯,用一个二进制表示每个操作会关掉哪几盏灯,那么两个操作一起做的话关掉的就是这两个操作异或起来之后为1的那几盏

      还有,如果有一堆数,每个数有一个价值,要在满足取的数线性无关的前提下最大化价值,一般都是用贪心,下面的几道题里有。(具体证明我不会)

    例题

    洛谷P3857 [TJOI2008]彩灯

    洛谷P4301 [CQOI2013]新Nim游戏

    CF895C Square Subsets

    洛谷P4570 [BJWC2011]元素

    洛谷P3265 [JLOI2015]装备购买

    洛谷P3292 [SCOI2016]幸运数字

    洛谷P4151 [WC2011]最大XOR和路径

    CF724G Xor-matic Number of the Graph

  • 相关阅读:
    进程的理论基础
    笔记
    ssh socketserver
    redis基本类型和操作
    centos redis 安装
    spring data jpa 查询部分字段
    spring data jpa 查询部分字段列名无效问题
    多个ajax执行混乱问题
    spring data jpa使用原生sql查询
    idea修改变量及其引用
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9721149.html
Copyright © 2020-2023  润新知