zoukankan      html  css  js  c++  java
  • 线性基

    线性基

    基本概念:

    线性基的概念见:https://oi.men.ci/linear-basis-notes/

    通俗的讲就是给定你由N个整数构成的整数序列,你可以从中选取一些(至少一个)进行异或((XOR))运算,从而得到很多不同的结果。你能将这(N)个整数压缩成另一个序列,取其中的进行异或((XOR)),得到的结果和之前相同,其中(a[i])二进制的最高位的(1)在第(i)位,且满足一下特殊的性质,这就是线性基。

    构造线性基:

    实现:将整数x插入线性基,将整数x二进制从最高位开始往后枚举,找到最高位i的"1",判断是否能插入bas[i],若不能将x^bas[i],然后继续往后找

    ll bas[N];
    int sz=64;
    bool insert(ll x){
        for(int i=sz;i>=1;i--){
            if((x&(1ll<<(i-1)))==0) continue;
            if(bas[i]) x^=bas[i];
            else bas[i]=x;return true;
        }
        return false;
    }
    

    高斯消元版。

    bool insert(ll x){
        for(int i=sz;i>=1;i--){
            if((x&(1ll<<(i-1)))==0) continue;
            
            if(bas[i]){
            //若如主元j已经存在,用a[j]消去x的第j位然后继续
            	x^=bas[i];
                continue;
            }
            for(int j=1;j<=i-1;j++){
     		//让x当主元i,需要先用第j(j<i)个主元消去x的第j位
     			if(x&(1ll<<(j-1))) x^=bas[j];
            }
            for(int j=i+1;j<=sz;j++){
            //接着用x去消掉第j(j>i)个主元的第i位
                if(bas[j]&(1ll<<(i-1))) bas[j]^=x;  
            }
            bas[i]=x;
            return true;
        }
        return false;
    }
    

    线性基相关性质

    1.求任意子集xor最大值:把线性基中所有元素xor起来。

    ll qryMax(){
        ll ans=0;
        for(int i=1;i<=sz;i++){
            ans^=bas[i];
        }
        return ans;
    }
    

    2.求任意子集xor最小值: 等于最小的主元。

    ll qryMin(){
        for(int i=1;i<=sz;i++){
        	if(bas[i]) return bas[i];    
        }
    }
    

    3.查询第k小的值:把k进行二进制分解,把1对应位置的主元xor起来,注意这里第0小就是0。

    //快速幂
    ll ksm(ll x,ll p){
        ll res=1;
        while(p){
            if(p%2==1) res*=x;
            p/=2;
            x=x*x;
        }
        return res;
    }
     
    ll qry(ll k){
        if(ok) k--; //判断值域是否有0,有0则0为第1小
        if(k<=0) return 0;
        int cnt=count;//线性基大小
        ll res=0;
        for(int i=sz;i>=1;i--){
            if(bas[i]==0) continue;
            cnt--;
            if(k-ksm(2,cnt)<0) continue;
            res^=bas[i];//将k二进制拆分后1的位置
            k-=ksm(2,cnt);
        }
        if(k) return -1;//不存在的k小
        else return res;
    }
    

    4.查询x是否在值域中: 如果x能插入线性基,则x不能被当前线性基xor出来

    5.求任意子集与x进行xor的最大值:从高->低贪心,若xor上a[j]能变大就xor


    相关练习

    【P3812 【模板】线性基】https://www.luogu.com.cn/problem/P3812

    【P4570 [BJWC2011]元素】https://www.luogu.com.cn/problem/P4570

    【acwing229 新nim游戏】https://www.acwing.com/problem/content/231/

    【acwing210 异或运算】https://www.acwing.com/problem/content/212/

    【牛客练习赛76 牛牛数数】https://ac.nowcoder.com/acm/problem/214945

  • 相关阅读:
    理解钩子Hook以及在Thinkphp下利用钩子使用行为扩展
    ThinkPHP 分页类的使用及退出功能的实现
    ThinkPHP登录功能代码
    thinkphp遗留问题
    ThinkPHP随笔
    ThinkPhp循环出数据库中的内容并输出到模板
    thinkphp常用Config.php配置项
    thinkphp笔记
    PHP面向对象学习七 总结
    Trie树
  • 原文地址:https://www.cnblogs.com/kksk/p/14297759.html
Copyright © 2011-2022 走看看