• 线性基学习笔记


    概念

    线性基是向量空间的一组基,通常可以解决有关异或的一些题目。

    性质

    线性基有三大性质

    (1)、原序列里面的任意一个数都可以由线性基里面的一些数异或得到

    (2)、线性基里面的任意一些数异或起来都不能得到 (0)

    (3)、线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的

    线性基的题目一般都是对这三大性质的考察

    要想了解性质,我们首先要知道线性基是如何构造的

    构造

    对原集合的每个数 (p) 转为二进制,从高位向低位扫,对于第 (x) 位是 1 的,如果 (a_x) 不存在,那么令 (a_x=p) 并结束扫描,如果存在,令 (p=p xor a_x)

    代码

    void ad(long long now){
    	for(rg int i=60;i>=0;i--){
    		if(now==0) return;
    		if(now&1LL<<(i-1)){
    			if(d[i]){
    				now^=d[i];
    			} else {
    				d[i]=now;
    				return;
    			}
    		}
    	}
    }
    

    证明

    对于性质一,分两种情况讨论

    如果 (x) 没有插入成功,那么 (x) 必定在异或一些数后变成了 (0)

    就有 (d[i] xor d[j] xor d[k]...xor x=0)

    也就是 (d[i] xor d[j] xor d[k]...=x)

    如果 (x) 插入成功

    (d[i] xor d[j]...xor x=d[k])

    变一下就是 (d[i] xor d[j] xor d[k]...=x)

    对于性质二

    如果 (d[i] xor d[j] xor d[k]=0)

    那么较晚插入的那一个一定会被异或成 (0),不会插入线性基

    对于性质三

    目前不会证,建议看这篇博客

    用途

    (1)、查询 (n) 个数异或的最大值。

    从高位到低位贪心地选,如果异或当前位的线性基后答案变得更大就异或上,否则就不选

    代码

    void cx(){
    	long long ans=0;
    	for(rg int i=60;i>=0;i--){
    		if((ans^d[i])>ans) ans^=d[i];
    	}
    	printf("%lld
    ",ans);
    }
    

    (2)、查询 (n) 个数异或的最小值。

    就是线性基中最小的值

    如果有插入不成功的情况,答案就是 (0)

    (3)、查询某个数是否能被异或得到。

    看一下这个数能否成功插入线性基

    如果可以,就能被异或得到,否则不能

    (4)、查询 (n) 个数异或的 (k) 小值

    首先,要对这个序列的线性基处理一下,对于每一个 (d[i])

    枚举 (j=i o 1),如果 (d[i]_{(2)}) 的第 (j) 位为 (1)

    那么 (d[i] xor d[j-1])

    其实就是让每一个线性基提供自己最高位上的一

    这样,我们只需要把 (k) 进行二进制分解,贪心去选即可

    异或之后得到的数组仍然是一个线性基

    也就是说一个序列的线性基不唯一,只是元素数量唯一而已

    题目

    P4570 [BJWC2011]元素

    利用了性质三,贪心地选择

    P3857 [TJOI2008]彩灯

    同样利用了性质三

    P3292 [SCOI2016]幸运数字

    线性基可以支持 (RMQ)

  • 相关阅读:
    map & reduce
    Generator
    切片
    函数参数
    Dict & Set
    list,tuple
    selenium鼠标和键盘操作
    selenium元素定位以及点击事件
    css定位
    xpath
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14043479.html
Copyright © 2020-2023  润新知