• 线性基学习


    线性基介绍

    有一个序列 A A A,若存在一个序列 B B B,使得对于 A A A中任意若干个数的异或 k k k,一定有 B B B中的若干个数,使得这些数的异或和为 k k k,且 B B B是满足以上条件的长度最小的序列,则称 B B B A A A的线性基。

    线性基可以用来解决一些子集异或和的问题。

    线性基的性质

    1. 原序列的任意一个数都可以由线性基中的若干个数的异或和得到
    2. 线性基中任意若干个数的异或和不为 0 0 0
    3. 在保持性质1的前提下,数的个数最少

    线性基的构造

    设数组 d d d为数组 a a a的线性基( d d d 0 0 0开始),则我们可以得到 d d d的长度一定小于等于 a a a中的最大数的二进制的位数。为什么呢?如果 d i = 2 i d_i=2^i di=2i,则如果 d d d的长度与 a a a中最大数的位数,则 a a a中的每一个数都能按二进制位用 d i d_i di异或而得。

    我们规定:若 d i d_i di不为 0 0 0 d i d_i di的最高位为 i + 1 i+1 i+1。当然, d i d_i di 0 0 0表示 d i d_i di不存在。那么,我们可以构造数组 d d d

    code

    for(int i=1;i<=n;i++){
    	for(int j=mx;j>=0;j--){
    		if((a[i]>>j)&1){
    			if(!d[j]){
    				d[j]=a[i];
    				break;
    			}
    			a[i]^=d[j];
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对于每个 a i a_i ai,设 a i a_i ai的最高位为 k k k,若 d k − 1 = 0 d_{k-1}=0 dk1=0,则将 a i a_i ai赋给 d k − 1 d_{k-1} dk1,否则令 a i = a i ⊕ d k − 1 a_i=a_i\oplus d_{k-1} ai=aidk1。到最后一定能有若干个数能构成后来的 a i a_i ai,那么用 a i ⊕ d k − 1 a_i\oplus d_{k-1} aidk1就能得到先前的 a i a_i ai

    注:异或运算满足 a ⊕ b ⊕ b = a a\oplus b\oplus b=a abb=a


    例题

    n n n个数组成的一个可重集合 S S S,求一个集合 T ⊆ S T\subseteq S TS,使得 T 1 ⊕ T 2 ⊕ T 3 ⊕ ⋯ ⊕ T ∣ T ∣ T_1 \oplus T_2 \oplus T_3 \oplus \cdots \oplus T_{|T|} T1T2T3TT最大。

    • n ≤ 1 0 5 n\leq 10^5 n105
    • 0 ≤ S i ≤ 2 50 0\leq S_i\leq 2^{50} 0Si250

    构造 S S S的线性基 d d d,显然 S S S的最大异或和一定可以用 d d d中的若干个数的异或和得到。

    令答案为 a n s ans ans a n s ans ans的初始值为 0 0 0。我们按 d d d的下标从大到小遍历。对于每个 d i d_i di,若 a n s ⊕ d i > a n s ans\oplus d_i>ans ansdi>ans,则 a n s = a n s ⊕ d i ans=ans\oplus d_i ans=ansdi。为什么呢?在 i + 1 i+1 i+1位之前的的每一位不变的情况下,第 i + 1 i+1 i+1位如果是 0 0 0,则将其变为 1 1 1一定是更优的。因为在之后各个 a i a_i ai的第 i + 1 i+1 i+1位一定为 0 0 0,所以只有在这个数中才能将 a n s ans ans的这一位变为 1 1 1

    • a n s ans ans的第 i + 1 i+1 i+1位为 0 0 0,则显然 a n s ⊕ d i > a n s ans\oplus d_i>ans ansdi>ans
    • a n s ans ans的第 i + 1 i+1 i+1位为 1 1 1,则显然 a n s ⊕ d i < a n s ans\oplus d_iansdi<ans

    所以我们可以通过 a n s ⊕ d i ans\oplus d_i ansdi a n s ans ans的大小关系来决定是否要异或 d i d_i di

    code

    #include
    using namespace std;
    int n;
    long long ans=0,a[100005],d[55];
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&a[i]);
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=50;j>=0;j--){
    			if(a[i]&(1ll<<j)){
    				if(!d[j]){
    					d[j]=a[i];
    					break;
    				}
    				a[i]^=d[j];
    			}
    		}
    	}
    	for(int i=50;i>=0;i--){
    		if((ans^d[i])>ans) ans=ans^d[i];
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    【动画笔记】数据结构-AVL树的插入操作
    客户数据成为营销必备!成功关键是挖掘数据价值
    上新啦!请查收云原生虚拟数仓 PieCloudDB 十月动态
    unity 相机围绕物体旋转,并且有Y轴角度限制
    如何在Microsoft Exchange 2010中安装SSL证书
    10 个适用于 Windows 的最佳 PDF 编辑器,用于轻松编辑 PDF 文件
    python变量名解析总结
    vue-cli脚手架初始化项目+(node + webpack + 淘宝镜像)
    呕心沥血 JavaScript知识点梳理大全,超详细 建议收藏!!!
    Elk-Metricbeat配置Tomcat的日志分析 (Metricbeat-part3)
  • 原文地址:https://blog.csdn.net/tanjunming2020/article/details/128208594