zoukankan      html  css  js  c++  java
  • 线性基证明及使用

    线性基使用及证明

    定义

    线性基就是从一堆序列中,构造出一个序列,该序列通过异或组合可以组成原序列的任一一个序列(也就是线性代数所学的极大无关组的异或形式,也可以说是低配极大无关组,所以极大无关组满足的性质其都满足)

    性质

    性质1

    由线性基可以异或出原序列的任一一个数

    证明:由原序列求出一个线性基,设一个不在线性基的数为x,x不能被线性基异或得,则x可以插入线性基,则与线性基的定义矛盾,故得证

    性质2

    线性基中的数异或起来不能产生0

    证明:设线性基里由(a_1...a_n)(a_{b_1}igoplus a_{b_2}igoplus a_{b_3}=0)那么有(a_{b_1}igoplus a_{b_2} =a_{b_3})所以只需要(a_{b_1} a_{b_2})就可以表示原序列所有的数,所以线性基容量可以缩小,这与极大无关组的定义矛盾,得证

    性质3

    线性基的向量个数一定

    证明 若同一组向量组存在两组线性基(a_{b_1} a_{b_2} a_{b_3})(a_{c_1} a_{c_2})那么由线性基的定义,第二组线性基可以表示出第一组线性基的所有变量,那么由极大无关组定义,可以把第一组线性基 转换为第二组的线性组合,转化之后,组内相互异或仍然是线性基,所以第一组进行线性组合异或后,必然产生(a_{c_1} a_{c_2},a_{c_2})这种形式的向量组合,所以可以产生异或起来为0的情况,导致性质2不满足,矛盾。扩大的情况同理。所以线性基的向量个数一定
    (线代丢好久了,可能证明存在纰漏)

    插入

    void insert(LL c){
        for (int i=51;i>=0;i--){
            if (c&bit[i]){
                if (!xxj[i]){
                    xxj[i]=c;
                    break;
                }
                c=c^xxj[i];
            }
        }
    }
    

    等于说在模拟一个插入的过程,从高位向低位插入,如果这一位之前没有数,直接插入即可,如果有这异或这个数继续往低位找
    为什么是正确的呢 ? 因为假设这个位还没有数,那么想要表示这个要插入的数,直接把这个数插入线性基即可,如果这个当前最高位有数 那么这一位就可以用这个当前最高位存的数表示出来,把cxxj[i]看剩下的位能不能表示继续找即可(因为c=cxxj[i]^xx[j]))在这个插入过程中异或所发生的变化可以还原回来

    合并

    暴力一个一个怼就另外一个即可

    删除

    贵校线性代数没学过吧,有没有大佬教一下?

    取最大值

    从最高位开始异或即可 如果当前值异或这个值会变大,直接异或即可,这里运用了贪心的思想,因为二进制高位等于前面所以低位取1再加1,所以取高位为1是比所有低位任一组合都赚的。

    LL query_max(){
        LL ret=0;
        for (int i=51;i>=0;i--){
            if ((xxj[i]^ret)>ret) ret=ret^xxj[i];
        }
        return ret;
    }
    

    xor d最小值

    ret=d 扔进query_max()

    最小值

    和最大值同理,不过是取最小位有值的那个数罢了

    第k小

    先用一个可以说是标准化的过程,把xxj[i]这一个数的第i位保留,把其他的第i位置成0,然后就可以很方便得求第k小了,例如第一小是最小的i的那个数,第二小 是倒数第二小的i的那个数,第三小就是 第一小第二小异或,有没有发现什么规律,那就是把第k小转化为二进制形式,然后把所以位数为1的进行异或即可

    void rebuild()
    {
        for (int i=60;i>=0;i--)
            for (int j=i-1;j>=0;j--)
                if (d[i]&(1LL<<j))
                    d[i]^=d[j];
        for (int i=0;i<=60;i++)
            if (d[i])
                p[cnt++]=d[i];
    }
    long long kthquery(long long k)
    {
        int ret=0;
        if (k>=(1LL<<cnt))
            return -1;
        for (int i=60;i>=0;i--)
            if (k&(1LL<<i))
                ret^=p[i];
        return ret;
    }
    

    Reference

    代码来源及参考:
    https://www.cnblogs.com/Michael-Li/p/8734708.html
    证明启发:
    https://blog.csdn.net/a_forever_dream/article/details/83654397
    感谢以上两位博主,如有侵权,请联系,马上删除。

  • 相关阅读:
    检测ORACLE方法汇总数据块损坏
    DHot.exe 热点新闻
    无效 URI: 故障分析证书颁发机构/主机
    lucene两个分页操作
    求职技巧—2014六个秘诀二
    ubuntu下一个rootusername入口mysql,如何查看username和password,如何改变rootpassword
    LeetCodeOJ. Maximum Depth of Binary Tree
    基于用户的推荐协同过滤算法的算法
    《C++ Primer Plus》学习笔记10
    m_Orchestrate learning system---八、下拉列表(select标签)如何实现链接功能
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/11235344.html
Copyright © 2011-2022 走看看