• 线性相关/线性基


    线性基有啥用

    例题:P3812 【模板】线性基

    我们有些时候会遇到类似这样的问题:给定一组数字,求异或和最大值。

    我们可以用线性基来解决这个问题。

    怎么构建线性基呢

    那么我们怎么考虑这个问题呢?

    我们可以类比于向量。

    在向量中,我们可以用单位向量表示某一个方向上的单位量。并且我们能用n个单位向量导出一个$n$维的空间。

    同理对于异或空间也是可以线性基来导出的。

    我们可以把一个长整型看成$64$维的向量,每个方向为$0$或$1$。

    我们考虑一个数能导出怎样的一个单位向量呢?

    我们发现如果是单位向量,那么这个向量除了当前这个方向上为$1$,其余都是$0$。

    但是在这里我们可以放宽这个要求,我们要求高位上全为$0$,这一位为$1$。

    如果前$k$维的单位向量都已经被成功导出,那么我们就可以完全地掌控前$k$维的空间了。

    大致就是这个意思。

    我们考虑插入一个数的操作。

    我们从高位(维)向低位(维)遍历,如果我们发现当前第$i$位上为$1$,也就说明了这一个数对这个$i$维空间有影响。

    我们判断一下,当前这个空间是否已经被成功导出了,如果已经被导出的话,我们就有办法消除这个影响,也就是异或上当前这个空间的单位向量。

    如果没有被成功导出,那么我们最高就能影响到当前这个空间了,记录这个向量为当前空间的单位向量,结束循环。

    有没有插入失败的情况呢?

    有,就是当前这个向量能被完全消除影响,也就是说能被之前的向量导出的时候。

    线性相关

    给定一个线性空间,如果一个向量存在于这个空间中,就是说这个向量和这个空间线性相关。

    这个线性空间是由一个向量集合导出的,具体见上面线性基的介绍。

    例题:P3265 [JLOI2015]装备购买

    常用模板

    下面给一些常用的模板

    插入元素

    1 void Insert(ll a){
    2     for(int i=63;i>=0;i--)if(a&(1LL<<i)){
    3         if(num[i])a^=num[i];
    4         else {
    5             num[i]=a;
    6             return;
    7         }
    8     }
    9 }
    View Code

    查询某元素能否被表出

    1 bool Inside(ll x){
    2     if(!x)return 1;
    3     for(int i=63;i>=0;i--)if(x&(1ll<<i)){
    4         if(num[i])x^=num[i];
    5         else return 0;
    6         if(!x)return 1;
    7     }
    8     return 0;
    9 }
    View Code

    查询能表出的最大值

    1 ll query_maxn(){
    2     ll now=0;
    3     for(int i=63;i>=0;i--)
    4         if((now^num[i])>now)
    5             now^=num[i];
    6     return now;
    7 }
    View Code

    查询能表出的最小值

    1 ll query_minn(){
    2     for(int i=0;i<=63;i++)
    3         if(num[i])return num[i];
    4     return 0;
    5 }
    View Code

    查询表出的第k小值

    我们要查询第$k$小值,首先必须得让每一个单位向量能影响的范围独立,也就是说当前向量的选取对其他的向量没有影响。

    之前我们保证了高位独立,这时候我们要重新建基,建一个新基,保证高位独立并且低位也独立。

    并且按照独立团的个数进行重编号,那么第k大的数就相当于重编号后的$k$所对应的二进制数的异或和

     1 void rebuild(){
     2     for(int i=1;i<=63;i++)
     3         for(int j=i-1;j>=0;j--)
     4             if(num[i]&(1LL<<j))
     5                 num[i]^=num[j];
     6     for(int i=0;i<=63;i++)
     7         if(num[i])
     8             p[cnt++]=d[i];
     9 }
    10 ll query_kth(ll k){
    11     ll now=0;
    12     if(k>=(1LL<<cnt))return -1;
    13     for(int i=63;i>=0;i--)
    14         if(k&(1LL<<i))
    15             now^=p[i];
    16     return now;
    17 }
    View Code
  • 相关阅读:
    WCF+Silverlight 制作一个简单RSS的阅读器(一)
    将Ironpython嵌入到你的程序中
    今天修改了网页
    开发小议
    Silverlight 可以支持windows2000了
    昨天晚上开始寻找圣诞的素材了
    需要每天的坚持!
    今天开始学习ADO.NET中的Connection对象(一)SqlConnection对象连接SQL Server
    一个基于Ajax简单的数据验证
    《微软:DirectShow开发指南》第4章 Capturing Audio with DirectShow
  • 原文地址:https://www.cnblogs.com/onglublog/p/10047933.html
Copyright © 2020-2023  润新知