zoukankan      html  css  js  c++  java
  • 线性基简单学习笔记

    线性基

    • 百度百科【IN
      百度的第一句话似乎有点怪异

    其实,对于广义的线性基,也就是线性代数里面的。一个基也相当于该空间内的一个集合。

    其实一个基的最大的特点就是:

    1. 它可以线性表出所有该空间里的向量(元素)
    2. 它的大小是最小的(也就是基中的元素个数不多)
    3. 且它的任何一个非空子集不会线性表出空集。

    对于线性表出的意思,可以简单的理解为一些元素通过一种运算可以得到另一个元素,就称这些元素线性表出了另一个元素(线性表示出的意思)

    关于第三点,可以简单证明一下,用反证法:
    假如,对于i=1nai=igoplus_{i=1}^na_i=varnothing,那么我们将左边的一个元素移动到右边,则变成了i=1nai[i̸=j]=ajigoplus_{i=1}^na_i[i ot= j]=a_j,那么aja_j这个元素就可以被i=1nai[i̸=j]igoplus_{i=1}^na_i[i ot= j]线性表出了,所以将aja_j删除,剩下的才是线性基。

    这里,我们只讲在异或意义下的线性基,也就是=xorigoplus=xor


    除了对于数在二进制下的异或,我们可以将其推广到集合上,也就变成了对称差,那么可以用同样的方式对于一系列集合求其线性基。


    一些定义:

    • 异或和

    这里我们的异或和不是ai xor aj+ak xor awa_i xor a_j +a_k xor a_wcdots,而是xori=1nai{xor}_{i=1}^na_i,也就是所有的aia_i异或起来。其中aia_i为无符号的整数类型。

    • 线性相关

    学过线性代数的人应该知道吧QAQ
    对于一个集合SS和集合中的任意一个元素sjs_j,这个sjs_j可以由集合中的其它元素线性表出,那么就称集合SS线性相关,反之就如果所有的sis_i都不满足该性质,就称为线性无关。

    • 张成

    对于一个集合SS的张成,我们简记为span(S) m span(S),其中:
    span(S)={tt=siSsi}(SS) m span(S)={t|t=igoplus_{s_iin S^{'}}s_i}(S^{'}为S的子集)
    用文字来说,就是对于每一个SS的子集的线性运算结果所组成的集合称作这个集合的张成。

    一个结论就是对于一个线性相关的集合SS,去除其中任意一个元素,它的张成不变(因为这个去除的元素可以由其他的表出),这个也可以来证明最开始的特点3。


    这里我们来定义线性基:

    线性基

    我们称一个集合(基)XXSS的线性基,当且仅当:

    1. XX是线性无关的(如果线性相关的话,我们可以将一些可以表出的元素删除,因为要保证最小,所以必须线性无关)
    2. Sspan(B)Ssubseteq m span(B),也就是这个集合SS可以由XX线性表出(SSXX的张成子集)。
    • 性质
    1. XX是最小的满足条件的集合,它的任何真子集都不可能是新的线性基,因为少了任何一个元素,那么由于线性无关,这个元素就不能被剩下的表出了,那么就不符合条件2。
    2. SS中的任意元素都可以被XX线性表出。(其实也就是条件2)

    构造

    我们这里只讲在异或的运算下如何快速构造:

    对于一个无符号(非负数)整数集SS,我们令它的元素最大二进制位的个数为LL,我们可以发现,只需对于每一位存储一个元素,那么就可以表出所有的了,所以我们可以构造一个log(max{si})log(max{s_i})大小的线性基。

    构造方式为将每个元素sis_i插入线性基,那么复杂度就为O(Slog(max{si}))O(|S|log(max{s_i}))

    所以我们令XX为其线性基,那么可以安照如下方式构造:

    • 从高位到低位扫描sis_i
    1. xi=0x_i=0时且sis_iii位为11,那么我们令xi=six_i=s_i,然后即可停止扫描,因为到插入sis_i为止,只有sis_i能表出第ii位的11
    2. xi̸=0x_i ot=0时,由于这一位已经可以表出了,所以我们将sis_i异或上这一位的值,继续扫描(因为要保证可以表出每一位且线性无关)。

    那么构造方式就是这样,代码实现非常简单,如下:

    void insert(int si){
    	for(int i=maxbit;i>=0;i--){
    		if(!(si>>i)&1) continue;
    		if(!X[i]){X[i]=si;return;}
    		si^=X[i];
    	}
    }
    

    对于合并两个线性基,就是将一个线性基中的元素插入另一个,复杂度为(log(max{si}))2(log(max{s_i}))^2


    应用

    1. 给出你一个集合SS,和一个数字aa,让你求a xor sia xor s_i最大:其实这个就扫一遍sis_i即可,不用线性基。
    2. 给出你一个集合SS,和一个数字aa,让你判断这个集合能否表出(异或出)aa:先求出线性基,我们就从二进制高位到低位扫描,如果第ii位为11,那么就将a xor xia xor x_i,如果最终a=0a=0则表示可以(也就是看能否插入线性基,如果不能插入则就可以表示出来,根据线性基的定义即可知道)。
    3. 给你一个集合SS,求出这个集合能够异或出的最大值:我们求出SS的线性基,然后扫一遍,每次取ans=max{ans,ans xor xi}ans=max{ans,ans xor x_i}即为答案。

    End

    若有错,请及时提出联系博主
    萌新才学QWQ


    洛谷模板IN

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int M=65;
    ll rec[M],a,ans;
    void insert(ll a){
    	for(int i=61;i>=0;i--){
    		if(!(a>>i)&1) continue;
    		if(!rec[i]){rec[i]=a;return;}
    		a^=rec[i];
    	}
    }
    ll getmax(){
    	for(int i=61;i>=0;i--)ans=max(ans,ans^rec[i]);
    	printf("%lld
    ",ans);
    }
    int n;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%lld",&a),insert(a);
    	getmax();
    	return 0;
    }
    

    参考学习博客:

    menci-Orz%%%
    ljh2000-Orz%%%

  • 相关阅读:
    8.JavaCC官方入门指南-例3
    7.JavaCC官方入门指南-例2
    6.JavaCC官方入门指南-例1
    5.JavaCC官方入门指南-概述
    4.JavaCC处理中文字符
    3.JavaCC 语法描述文件的格式解析
    2.idea安装JavaCC插件.md
    SQL 高效运行注意事项(二)
    视图用到的表更新表结构时注意刷新视图
    SQL 高效运行注意事项(一)
  • 原文地址:https://www.cnblogs.com/VictoryCzt/p/10053398.html
Copyright © 2011-2022 走看看