线性基是一个奇妙的集合(我摘的原话)

这里以非 $OI$ 的角度介绍了线性基

基础部分

模板题

给你 $n$ 个数的集合,让你选出任意多个不重复的数,使得它们的异或和最大。

线性基是什么

我们称集合 $B$ 是集合 $S$ 的线性基,当且仅当 集合 $B$ 和 集合 $S$ 的元素数相同,且集合 $B$ $=$ 集合 $S$ 能异或出的数的集合。

其中“能异或出的数的集合”表示从集合中选出任意多个数(不能不选),它们的异或和组成的集合。

怎么构造线性基

异或是基于二进制的,我们当然要以二进制位的角度考虑啦!

我们依次插入每个给定集合 $S$ 的数,设我们要往集合 $B$ 中插入一个集合 $S$ 的数 $x$,我们将 $x$ 从高往低位遍历二进制位。

设当前遍历到第 $i$ 位,

若遇到 $1$,则判断之前是否已插入过最高位为 $1$ 的数(设其为 $p_i$):

- 如果插入过,就把当前要插入的数异或上 $p_i$,再往低位遍历;

- 如果没插入过,就把当前插入的数赋给 $p_i$,退出。

可以通过数学归纳法(从 $p_i$ 和从高到低位消 $1$ 两个角度)证明,这样构造使 $p_i$ 的值的最高二进制位是第 $i$ 位(这一位当然就是 $1$ 了)。

对于“$p_i$ 的值的最高二进制位是第 $i$ 位”这部分,一开始 $p$ 数组都未被赋过值,满足定义;然后如果另一部分是正确的,那赋值之后 $p$ 数组依然满足定义。

对于“从高到低位消 $1$”这部分,如果另一部分是正确的,每次异或 $p_i$ 都不会对更高位造成影响(那些位还是 $0$),第 $i$ 位会被消成 $0$,所以只有更低位可能有 $1$,往下遍历就行了。

已经说过,一开始 $p$ 数组满足定义,所以第一部分正确,然后两部分互相归纳下去即可完成证明。

我们把这个数组 $p$ 称作“有序的”集合 $B$ 吧!(因为集合本身有无序性)

据说这种构造方式很像高斯消元?这个还不是,下文会说怎么构造才是。

这样构造的意义是什么

对于集合 $S$ 中的任意两个数 $x,y$,它们能异或出的三种数是(假设不能一个都不取,即不取空集)$x,y,x\bigoplus y$。

由于异或的偶数抵消(即偶数个相同的数相异或等于 $0$,比如 $x\bigoplus (x\bigoplus y) = y$)性质,我们可以把 $x$ 和 $y$ 的任意一个换成 $x\bigoplus y$,这两个数能异或出的三种数依然是 $x,y,x\bigoplus y$。

拓展:把两个 $S$ 的子集中的数任意互相异或,再把两个子集合并得到的子集 能异或出的数的集合 $B_1$ 与把任意互相异或之前的子集合并得到的子集 能异或出的数的集合 $B_2$ 相等。

重要结论:所以我们把原集合 $S$ 中的数任意互相异或,集合 $S$ 能异或出的数的集合 $B$ 不变。

由于我们构造线性基的方式中,每个 $p_i$ 都是原集合 $S$ 中若干个数的异或和,所以集合 $p$ 能异或出的数的集合 与原集合 $S$ 能异或出的数的集合相等。

那为什么要把要插入的数 $x$ 不断异或 $p_i$?

对于一个新插入线性基的数,根据前述构造方式,如果从高到低遍历完所有二进制位,都没能插入给一个 $p_i$,那这个数必定被异或成了 $0$。

证明:

- 从高到低遍历到第 $i$ 个二进制位时,只有当前要插入的数 $x$ 的第 $i$ 位为 $1$ 时才会考虑异或 $p_i$。

- $p_i$ 的值的最高二进制位就是第 $i$ 位(之前证明过),且这一位为 $1$。

结合这两条,我们发现,要插入的数 $x$ 一定会被从高到低位依次被异或成 $0$,而且已经遍历过的高位不会再被异或成 $1$

在遍历最高位时,这个性质是成立的,而往低位遍历时,可以结合上述两条,用数学归纳法证明。

所以,遍历完所有位之后,如果 $x$ 还没被插入,就肯定被一堆 $p_i$ 异或成 $0$ 了。

这是什么意思呢?

说明 $x$ 一开始的值(就是在集合 $S$ 中的值)是能通过其它若干个数异或出来的(之前说过,$p_i$ 都是原集合 $S$ 的若干个数的异或和)。

那就已经能被表示了,所以不要它了。

综上,可以看出这个线性基最叼的地方是:它能把原集合构造成元素很少的新集合,使其能异或出的数的集合不变,且新集合能容纳一些特殊性质。

那模板题怎么做

我们发现,在线性基中,每种最高位的数只有一个(一个 $p_i$ 对应一个最高位)。构造完线性基后,我们从高往低再遍历一次二进制位,做贪心(因为高位的一个 $1$ 比低位的任意多个 $1$ 都大)。

具体地说,就是设当前最大值变量为 $ans$,初始时使 $ans$ 为 $0$,从高往低遍历到第 $i$ 位时,如果 $ans\bigoplus p_i\gt ans$,就更新 $ans$ 为 $ans\bigoplus p_i$。

证明:可以这样考虑,遍历到第 $i$ 位时,比第 $i$ 位高的位都已经极大,然后我们现在要确保第 $i$ 位极大。结合数学归纳法可知,高位优先大的贪心策略能保证答案最大。

拓展部分

请确保基础部分都会了再看这部分

首先说一个线性基特别重要的性质:一个线性基能异或出的每个数的组成方案是唯一的。换句话说就是对于一个线性基的任意两个不同的取数方案,异或出的数两两不相等。

原因很简单,根据之前说过的构造方法,如果新插入的一个数能被线性基中已有的数表示出来,那它在遍历完所有二进制位后也不会被插入,且它一定被若干个 $p_i$ 异或成 $0$。

由此可以推出 $2$ 个性质:

- 线性基能异或出的数一定不包括 $0$(包括 $0$ 说明线性基中有两个相等的数,其中一个就能被另一个表示了,不符合构造要求;而且线性基中每种最高位的数只能有一个,显然两个相等的数的最高位也是相等的,也不符合构造要求)

- 假设线性基中有 $cnt$ 个数,线性基能异或出的数的集合大小为 $2^{cnt}-1$($-1$ 就是去掉一个数都不取的情况)

(这些概念是给你深入学习用的,可能会有用)

模板题加强版

给你 $n$ 个数的集合,让你选出任意多个不重复的数,使得它们的异或和再异或一个常量 $s$ 最大。

题解

做之前的模板题时,我们让 $ans$ 一开始为 $0$。

这是为什么?

由于异或的性质,一个数异或 $0$ 等于这个数本身,所以我们可以把之前的模板题看做 要求若干个数的异或和再异或一个常量 $0$ 最大。

又因为异或有交换律,所以我们可以交换顺序,读作“要求一个常量 $0$ 异或若干个数的异或和最大”。

这道题同理。所以让 $ans$ 一开始为 $s$,再跟之前的模板题一样做最大值贪心就行了。

(这是我自己想出来的解释,好像没那么严谨)

XOR (HDU3949)

给你 $n$ 个数的集合,让你选出任意多个不重复的数(至少选一个),把它们的异或和放入一个新集合中(集合是有互异性的,相同的数只保留一个),求新集合的第 $k$ 小值。

简化题意:求线性基能异或出的数的集合的第 $k$ 小(其实某些情况下是 $k-1$,后面会说)。

题解

首先,对于这道题,线性基的构造方式就跟之前不太一样了,因为之前只要求最大,而现在要求第 $k$ 小。

但我们知道,线性基是以每个二进制为最高位存一个数的,那是不是容易想到把 $k$ 进制分解呢?

这样的话,在前文的构造方式的基础上,我们只需要改点限制:规定 $p_i$ 的值的最高位是第 $i$ 位,且在此基础上 $p_i$ 最小

直接加了一个最小的限制,这怎么做?

考虑之前的 $p_i$,它除了在第 $i$ 位有个 $1$ 外,在更低的位还有若干个 $1$。

那我们是否可以用线性基中的某些数,尽量消去低位的那些 $1$?(我们知道,线性基中的数都是原集合 $S$ 的若干个数的异或和,线性基中两个数的异或和还是原集合 $S$ 的若干个数的异或和)

这个很好做,往线性基插入一个新数时,用这个 $p_i$ 更新 $p$ 数组的其它所有值就行了。

详细做法:

  - 对于低位

    现在插入的一个数放到了 $p_i$,它在一个更低的二进制位(设其为第 $j$ 位)上为 $1$,且 $p_j$ 已被赋过值,那就把 $p_i$ 更新为 $p_i\bigoplus p_j$。

    证明:这种情况下让 $p_i$ 异或 $p_j$,不会对比第 $j$ 位更高的位造成影响,但会使 $p_i$ 的第 $j$ 位变成 $0$,这种情况下即使更低的位异或出再多的 $1$,这个数总体也变小了。

    为了方便,从大到小枚举 $j$ 即可。

  - 对于高位

    只考虑低位显然不对,因为有可能 $p_i$ 的第 $j$ 个二进制位为 $1$,而 $p_j$ 此时可能没有值,但它以后被赋了值,这种情况下也应该用 $p_j$ 更新 $p_i$。

    我们只能用赋值晚的更新赋值早的,所以对于插入的一个数 $p_i$,不仅要用更低位的 $p_j$ 更新它,还要用它更新更高位的 $p_j$。

    这一部分依然从大到小枚举 $j$。

这样就把线性基中的所有数都互相更新成满足限制的最小值,具体见代码吧(反正很短)。

其实这才是线性基的通用构造方式(比如对于模板题,多出来的要求对答案没有影响,因此该构造方案可以兼容使用)。另外说一下,换个角度看这个构造方式,其实就是标准的高斯消元+矩阵消成三角形,文章开头给了个非 $OI$ 角度介绍线性基的链接,可以去那里看看矩阵高斯消元的讲解。那里所谓的把不在对角线上的 $1$ 能消掉就消掉,其实也就是让每行的数最小。异曲同工吧?

如上改变线性基的构造方式后,把 $k-1$ 二进制分解,若第 $i$ 位为 $1$ 就把 $ans$ 异或上 $p_i$。

证明比较冗杂(其实是不会表达),这里尽量短地说一下(其实还是很长):

你会发现,若 $p_i$ 的第 $j$ 个二进制位是 $1$,那 $p_j$ 一定没被赋过值(如果有值就能更新 $p_i$ 使其更小了)。

所以所有的 $p_i$ 在各自的位数范围内(就是不超过最高位)都必须且只能在某些相同的位上有 $1$。

比如线性基里的三个数(二进制表示)可能是这样的(高位自动补成 $0$,用于对齐,其实不用考虑):$$111\space\space 011\space\space 001$$

而不可能是这样的:$$111\space\space 010\space\space 001$$

因为最低位要么都是 $1$,要么都是 $0$(也就是说要么最低位的 $p_i$ 有值,要么没值,不能模棱两可)。

这样的话,有一个烦人的顾虑就没了。

这个顾虑我不知道怎么叫名字……

大概就是说,如果 $p_i$ 表示线性基中最高位二进制位为 $i$ 的数,我们知道第 $2^{i-1}$ 大异或和为 $p_i$,第 $2^{j-1}$ 大异或和为 $p_j$,但 $p_i\bigoplus p_j$ 不一定是第 $2^{i-1}+2^{j-1}$ 大异或和(如果直接是的话,证明早就结束了)。

因为两数异或后第 $i$ 到 $j-1$ 位的数是不用争议的达到最小了(因为只有 $p_i$ 有那些位),但第 $j$ 位及以后的位根本没有保证啊!

为了解决这些顾虑,我们拆开考虑:

对于第 $j$ 位,$p_i$ 的第 $j$ 位必定是 $0$,因为 $p_j$ 被赋过值。

对于更低的位,$p_i$ 和 $p_j$ 在那些位上的数完全相同,即一位要么都是 $1$,要么都是 $0$。

由于我们前面的新构造方式 是考虑把每个 $p_i$ 的 $1$ 消成 $0$,因此如果我们想得到其它的异或和,只能不消 $p_i$ 的 $1$,也就是把一些 $0$ 改回 $1$。

显然,只有 $p_i$ 为 $1$ 的位才有可能在与其它若干个 $p_j$ 异或后得 $1$(异或奇数次),而 $p_i$ 为 $0$ 的位在异或后,这一位肯定还是 $0$(因为异或的那些 $p_i$ 在同位也必须是 $0$)。

保留 $p_i$ 原有的 $1$,而再把 $0$ 改成 $1$,$p_i$ 在与其它若干个 $p_j$ 的异或和 只可能在把原异或和(就是把 $p_i$ 的 $0$ 改成 $1$ 之前与这些 $p_j$ 的异或和)的某些二进制位由 $0$ 变成 $1$,新的异或和显然不会变小。

所以顾虑就解决了, $p_i\bigoplus p_j$ 在第 $j$ 位及更低位的部分的数 已经达到最小,结合二进制原理可得 $p_i\bigoplus p_j$ 是第 $2^{i-1}+2^{j-1}$ 大异或和。

做完了?

然而这道题还有个比较坑的地方……

就是它要求至少选一个数,也就是不能不选(这种情况下异或和为 $0$),但你可以选出若干个数(至少一个)的异或和为 $0$(这种情况下 $0$ 才是最小的异或和),然而线性基中的数并不能异或出 $0$(因为任意两个数的最高位都不相同,至少最大的那个数的高位就消不掉),所以我们要特判能否异或出 $0$。

这个也很好判,回顾一下线性基的构造:你在往线性基中插数的时候,如果最终这个数没被插入,那它一定就被异或成 $0$ 了。这说明原集合 $S$ 的若干个数(至少一个)能异或出 $0$,这时把 $k$ 改为 $k-1$ 即可。

Xor(WC2011 / bzoj2115)

给定一个 $n(n\le 50000)$ 个点 $m(m\le 10000)$ 条边的无向图,每条边上有一个权值。请你求一条从 $1$ 到 $n$ 的路径,使得路径上的边的异或和最大。

路径可以重复经过某些点或边,当一条边在路径中出现了多次时,其权值在计算异或和时也要被计算相应多的次数。

注意:这条路径可以多次经过 $1$ 和 $n$,只要路径的第一个点是 $1$ 且最后一个点是 $n$ 即可。

可能有重边、自环。

题解

其实这题的重点是图论找性质……

如果路径不可以重复经过点边,那这就是我们常见的简单路径了,直着从起点连到终点的那一种。

如果路径可以重复经过点边,简单路径本身不会变(因为你肯定要从起点走到终点),变的只是可以多走一些环。

容易发现,一条可以重复经过点边的路径的异或和 相当于一条从起点到终点的简单路径的异或和 异或 若干个(可以是 $0$ 个)任意的环的异或和。

哪里来的若干个任意的环?

思考一下,从简单路径上的任意一点出发,到达一个环,跑一圈,再原路返回,从简单路径上的点到那个环的往返路径走了两次,异或和抵消为 $0$,因此实际上就多了一圈环的异或和。

那可不可以去跑一圈环套环(或者多个环套起来)呢?也是可以的。这样的话每个环依然都恰好被跑了一次,异或和就是 这些环上所有边权的异或和相异或。

由此也很容易看出,每个环至多只需要考虑跑一次(即算一次异或和)。因为跑偶数次的话,环的异或和会被抵消为 $0$,因此多就是算一次环的异或和,那跟跑一圈一样。

所以把图中的所有环提出来($DFS$ 根据生成树的返祖边找环),记下每个环上所有边权的异或和。

然后枚举每条简单路径,求出该简单路径的异或和(设其为 $s$),问题变成了找若干个环,使这些环的异或和相异或 再异或 $s$ 最大。这就是前文讲过的模板题加强版了。

这真的是很好的思维题啊!

Shallot(bzoj4184)

有一个一开始为空的集合,支持三种操作:加入一个数,删除一个数;每次完成前两种操作中的任意一个后,回答当前集合中若干个数的异或和最大是多少。

题解

动态线性基?麻麻我要离线

容易发现,线性基不支持删除……(想一想就知道了)

但可以离线,那线段树分治每个数出现的时间就行了(标记永久化),于是成了不用删除操作的裸题。

时间复杂度 $O(31\times n\times log(n))$。

albus就是要第一个出场

给定 $n(n\le 10000)$ 个数 $a_1, a_2, \ldots, a_n$,以及一个数 $Q$。将 $a_1, a_2, \ldots, a_n$ 的所有子集(可以为空)的异或值从小到大排序得到序列 $B$,请问 $Q$ 在 $B$ 中第一次出现的下标是多少?保证 $Q$ 在 $B$ 中出现。

题解

我靠结论题

我当我在学习

这题最关键的问题就是异或和不去重!

我们知道,线性基每种选数方案的异或和是互不相同的(前文证明过该结论)。

那我们考虑一下每个数出现了多少次。

不难想到,线性基里的数很少,那没插入线性基的那些数是怎么着来着?

没错,就是被线性基中若干个数异或成 $0$ 后扔掉了。也就是那些数已经能被线性基中的数异或出来了。

如果我们不扔掉这些数,把这些 $0$ 也插入线性基,那异或和会是什么情况?

就是随便用这些 $0$!

假设原集合给了 $n$ 个数,线性基大小为 $|B|$,那剩下的 $n-|B|$ 个数肯定就是这些 $0$ 了。

在放入这些 $0$ 之前,线性基的每种选数方案异或出了一个唯一的异或和(也就是只有这一种方案得到这个异或和),现在多了 $n-|B|$ 个 $0$,而每个 $0$ 都可以用或不用,总共就有 $2^{n-|B|}$ 种方案得到这个异或和。

之前讲过了求第 $k$ 小的方法,现在我们要找比一个数 $Q$ 小的异或和的数量,本来是二分,但由于是在二进制位上做,所以可以优化为 只要在原线性基中枚举每个 $p_i$,尝试一下把 $sum$ 异或上 $p_i$ 是否小于 $Q$,如果小于就异或上这个数就行了,顺便加上比这个数小的数的数量(就是 $2^i$)。最后别忘了答案 $+1$(因为问的是 $Q$ 本身的出现位置,要算上自己的排名,刚才统计的只是比它小的数的数量)。

做完这道题后才发现,原来随便给一堆数,每个能异或出的数的出现次数都相同?我fo啦……

后记

1. 线性基不资瓷删除

2. 线性基大小为所有数的最大二进制位数(这不是废话么)

3. 线性基(大概)不资瓷限定选数的数量

4. 怎么什么数学内容都能硬套到 $OI$ 中……

在美妙的数学王国中畅游

转载于:https://www.cnblogs.com/scx2015noip-as-php/p/linear_basic.html

【基础操作】线性基详解相关推荐

  1. Android基础总结: Camera2详解之一 API学习

    Camera2的API出来有些年头了,只是赶项目多次使用,没时间好好总结,年终了,正好结合google的官方Camera2demo 和开发中使用的情况,做个详细梳理,研究总结之后,才发现Camera2 ...

  2. 【Java基础】HashMap原理详解

    [Java基础]HashMap原理详解 HashMap的实现 1. 数组 2.线性链表 3.红黑树 3.1概述 3.2性质 4.HashMap扩容死锁 5. BATJ一线大厂技术栈 HashMap的实 ...

  3. 线性表详解(静态链表、单链表、双向链表、循环链表)

    目录 申明 1. 线性表的定义 2. 线性表的抽象数据类型 3. 线性表的顺序存储结构 3. 1 顺序存储定义 3. 2 顺序存储方式 3. 3 数据长度与线性表长度区别 3. 4 地址计算方法 4. ...

  4. LSTM入门必读:从入门基础到工作方式详解 By 机器之心2017年7月24日 12:57 长短期记忆(LSTM)是一种非常重要的神经网络技术,其在语音识别和自然语言处理等许多领域都得到了广泛的应用

    LSTM入门必读:从入门基础到工作方式详解 By 机器之心2017年7月24日 12:57 长短期记忆(LSTM)是一种非常重要的神经网络技术,其在语音识别和自然语言处理等许多领域都得到了广泛的应用. ...

  5. 判断数组中某个元素除自身外是否和其他数据不同_算法工程师要懂的3种算法数据结构:线性表详解...

    算法思想有很多,业界公认的常用算法思想有8种,分别是枚举.递推.递归.分治.贪心.试探法.动态迭代和模拟.当然8种只是一个大概的划分,是一个"仁者见仁.智者见智"的问题. 其实这些 ...

  6. MongoDB查询性能分析—— explain 操作返回结果详解

    MongoDB 提供 db.collection.explain(), cursort.explain() 及 explain 命令获取查询计划及查询计划执行统计信息. explain 结果将查询计划 ...

  7. 电子元器件从入门到精通pdf_电子元件入门基础,常用电子元器件详解大全作用-涨知识必读...

    1.电子元器件筛选的必要性 电子元器件的固有可靠性取决于产品的可靠性设计, 在产品的制造过程中, 由于人为因素或原材料. 工艺条件. 设备条件的波动, 最终的成品不可能全部达到预期的固有可靠性. 在每 ...

  8. ELKElasticSearch5.1基础概念及配置文件详解【转】

    1. 配置文件 elasticsearch/elasticsearch.yml 主配置文件 elasticsearch/jvm.options jvm参数配置文件 elasticsearch/log4 ...

  9. python装饰器详解-Python装饰器基础概念与用法详解

    本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自 ...

最新文章

  1. linux多开终端,如何使用Tmux终端多开工具
  2. GPE监控多台MySQL_zabbix监控多个服务器
  3. IoT -- (一) 物联网平台架构设计分析
  4. 用poi-3.6-20091214.jar 实现java给excel资料加密
  5. 微软披露首个由中国发现的蠕虫级漏洞 奇安信代码安全实验室获致谢
  6. C# 在winform中如何为按钮设置快捷键( F1)
  7. java递归用for实现_用java实现的经典递归算法
  8. excel导出 服务器运行失败,SolidWorks 插入自制EXCEL明细表 启动服务器应用程序失败:启动excle服务器失败...
  9. mysql输出九九乘法表_SQL 打印九九乘法表
  10. 解读一淘网(etao)首页响应式兼容ie6~ie8实现方法
  11. html语言字体大小修改,html怎么修改字体大小
  12. unbuntu 中部署jenkins
  13. Disparity Map
  14. RT201 国产PA射频功率放大器 兼容RFX2401C
  15. 筋斗云接口编程 / 常用操作(二)
  16. (10.3.5.6)软件验收报告文档模版
  17. java如何找出勾股数组_勾股数组 学习笔记
  18. 北航和北理工计算机专业哪个好,北理和北航哪个好?
  19. qdbus模块_Qt6各大模块变更概览:旨在成为未来主要开发平台
  20. 手机一键去水印的软件有什么

热门文章

  1. matlab入门之旅,MATLAB 入门之旅学习笔记
  2. java 会话共享_java – servlet如何工作?实例化,会话,共享变量和多线程
  3. matlab colorbar采用对数,matlab colorbar的使用 | 學步園
  4. android闹钟唤醒不准的原因_俄罗斯睡眠专家:闹钟铃声选错了,可能扰乱你的内分泌...
  5. CountDownLatch的理解和使用
  6. java中split以“.“ 、“\“、“|”分隔
  7. String str=Hello 与 String str=new String(“Hello”)一样吗?
  8. 后端技术:Nginx + Spring Boot 实现负载均衡
  9. 真相了!敲代码时,程序员戴耳机究竟在听什么?
  10. SpringBoot:搭建第一个Web程序