【学习笔记】线性基

Page Views Count

指异或线性基,用一组线性无关的基底表示一些数异或的信息。

性质#

  • 任意一个原序列中的数度都能被线性基的几个基底异或得到。

  • 线性基任意一个子集异或和不为 0

  • 一个序列对应多个线性基,但线性基的规模都一定,且是满足性质 1 中所有基底组成集合最小的一个。

证明将在插入操作中展开。

具体操作#

插入#

对于数 x,从高到低位枚举,如果这一位是 1,且目前这一位的基底还没有,就直接更新基底并退出;反之将 x 异或这一位的基底。

inline void insert(ll x){
    for(int i=62;i>=0;--i){
        if(x&(1ll<<i)){
            if(!bs[i]){
                bs[i]=x,++cnt;
                break;
            }
            else x^=bs[i];
        }
    }
    chk0=1;
}

对于性质 1,这样插入如果最终也没有更新过一个基底,那么一定是被异或为 0,也就是被表示出来了,反之相当于更新的基底异或上之前的位置,也得到了这个数。

对于性质 2,如果出现异或和为 0,那么最后一个数不会被插入。

对于性质 3,设想仅改变两个数 x,y 的插入顺序,而构成的线性基不同,那么一定会在一位产生分歧,即这一位被先插入的数 x 占据,讨论 y 最后是否被插入,如果没有被插入,则没有任何影响;如果被插入,那么原来插入在这个位置的数将会被顶替,就变成了又一个这样的问题,只不过是位置变低,依此归纳,最终最后一位被占据的将无法插入,也就是线性基规模是不变的。

查询是否可以被表示#

按照插入方法,判断最终是否为 0 即可。

inline bool query(ll x){
    for(int i=62;i>=0;--i){
        if(x&(1ll<<i)) x^=bs[i];
    }
    return !x;
}

查询异或最大值#

接下来我们的操作都等价到线性基上,线性基的每一个基底最高位都不同,这是很友好的性质。

从高到低枚举,这样多异或一个数不会改变更高位的值,于是贪心异或,如果可以变更大就异或。

inline ll query_max(){
    ll res=0;
    for(int i=62;i>=0;--i){
        if((res^bs[i])>res) res^=bs[i];
    }
    return res;
}

查询异或最小值#

如果可以出现 0,答案必然是 0,反之答案应该是最小的基底,因为只要有更大的基底参与,那么一定会在更高位上有 1,而大于这个数。

inline ll query_min(){
    if(chk0) return 0;
    for(int i=0;i<=62;++i){
        if(bs[i]) return bs[i];
    }
}

查询 k 小值#

相对较难。思考这样一个问题:如果基底都是 2k,的确满足了完全表示的性质,并且这种中规中矩的基底,可以直接根据 k 的二进制来得到,也就是说,不会因为多选取一个元素而导致结果更小,或者是说,基底互不干扰。

但这样不满足线性基最小规模,例如 (1011)2,(0001)2,两个基底 (1010)2,(0001)2 就满足了互不干扰和规模最小两个条件。

如何构造这种互不干扰的线性基?

实际上是对于一个高位基底,尽量地消去低位的 1,使得一个基底的最高位只在自己位置是 1,其余基底均为 0。这样的得到满足线性基性质却又可以进行上述查询的基底。

接下来类似于变进制转换,直接把 k 中对应位是 1 的基底异或起来即可。

inline void rebuild(){
    for(int i=62;i>=0;--i){
        for(int j=i-1;j>=0;--j){
            if(bs[i]&(1ll<<j)) bs[i]^=bs[j];
        }
    }
    for(int i=0;i<=62;++i){
        if(bs[i]) rbs[++tot]=bs[i];
    }
}
inline ll kth(ll k){
    if(chk0){
        if(k==1) return 0;
        --k;
    }
    ll res=0;
    for(int i=tot;i>=1;--i){
        if(k&(1ll<<i-1)) res^=rbs[i];
    }
    return res;
}

参考资料#

作者:SoyTony

出处:https://www.cnblogs.com/SoyTony/p/Learning_Notes_about_Linear_Basis.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   SoyTony  阅读(195)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示