线性基是什么

线性基是一个数的集合。

对于数的集合 A ,A的线性基是指,在 A 中选取任意多个数进行异或,得到的结果的值域,和 A 的线性基中数字异或的值域相同。这样对原数组元素的异或运算就可以转化为线性基中元素的异或运算。但线性基中的元素个数比原数组中的元素个数少得多,因此常用来解决一个数组中元素异或值的问题。

线性基的构造

先来看下面的性质:

设集合 A = { a 1 , a 2 , . . . , a n } A = \{a_1, a_2,...,a_n\} A={a1​,a2​,...,an​},将其中一个元素 a i a_i ai​ 用 a i ⊕ a j a_i \oplus a_j ai​⊕aj​( i ≠ j i \neq j i​=j)替换,得到集合 A = { a 1 , a 2 , . . . , a i ⊕ a j , . . . , a n } A = \{a_1, a_2, ... ,a_i \oplus a_j,...,a_n\} A={a1​,a2​,...,ai​⊕aj​,...,an​},则从集合 A 中选取一些值异或得到的结果,都能通过在集合 B 中选取一些值异或得到。

设 x = a k 1 ⊕ a k 2 ⊕ . . . . ⊕ a k m x = a_{k1} \oplus a_{k2} \oplus .... \oplus a_{km} x=ak1​⊕ak2​⊕....⊕akm​
如果这些数不包括 a i a_i ai​ ,那么这些数也在集合 B B B 中。
如果这些数包括 a i a_i ai​ 那么, a i a_i ai​ 可以用 ( a i ⊕ a j ) ⊕ a j (a_i \oplus a_j) \oplus a_j (ai​⊕aj​)⊕aj​ 替换,所以 x 也可以由集合 B B B得到。

线性基还有一个重要性质:所有元素不为0。因此如果原数组异或可能得到0的情况需要特判。

我们可以根据这两个性质,将原数组中的某些元素,用其和另一个元素的异或值代替,不会改变原数组异或值的值域,这样来构造线性基。
如果原数组中的两个数字 A A A和 B B B的二进制最高位的1在同一位,例如 A = 18 ( 10010 ) , B = 24 ( 11000 ) A=18 \ (10010),B=24 \ (11000) A=18 (10010),B=24 (11000),最高位的1都在第5位,那么我们可以用 A = A ⊕ B A = A \oplus B A=A⊕B 来代替 A A A,这样 A = 10 ( 1010 ) , B = 24 ( 11000 ) A=10 \ (1010),B=24 \ (11000) A=10 (1010),B=24 (11000),将最高位的1放在不同的位上。对原数组的每个元素进行这样的操作,使得每个元素最高位的1分别处于不同的位上,例如:
a 1 = 10010011 a1 = 10010011 a1=10010011
a 2 = 00101000 a2 = 00101000 a2=00101000
a 3 = 00010111 a3 = 00010111 a3=00010111
a 4 = 00000010 a4 = 00000010 a4=00000010
易知这样处理会将原数组的大小变为 log ⁡ 2 N \log_2{N} log2​N,因此线性基的复杂度为 O ( log ⁡ N ) O(\log{N}) O(logN)。那么消失的元素去了哪里呢?之前说过线性基的元素不为0,是由于线性基中 0 元素没有意义,因此那些大部分异或得到0的元素直接被排除在外了。

求线性基的过程是在线的,也就是说,可以随时在线性基中插入一个新数字,因此实际上我们可以直接边输入边插入,不需要数组 A A A来保存。

#include <cstdio>
#define ll long long int
ll b[101], temp;
//b[i]保存线性基中二进制最高位为第i位的数字
int flag, N;                 //flag标记原数组异或是否能得到0
void insert(ll x)            //在线性基中插入x
{for(int i=62;i>=0;i--)   //从高位向低位扫描 ,2^62大概1e18左右,即ai最大可以达到1e18{if(x&(1ll<<i))       //如果x的二进制的第i位是1{if(b[i])x ^= b[i];   //根据性质将x进行变换 else{b[i] = x;return;}}}flag = 1;return;
}
int main()
{scanf("%d", &N);for(int i=1;i<=N;i++){scanf("%lld", &temp);insert(temp);}return 0;
}

线性基求解的常见问题

求一组数能异或得到的最大值

即在一个数组中,取若干个数,使得它们的异或和最大。
从数组线性基的最高位向低位扫描,贪心地选取可以使结果变大的数字即可。

ll get_max()
{ll res = 0;for(int i=62;i>=0;i--){if((res^b[i])>res)res ^= b[i];}return res;
}
求一组数能异或得到的最小值

一个数组能异或得到的最小值,就是线性基中最小的元素,还要特判异或为0的情况。

ll get_min()
{if(flag) return 0;for(int i=0;i<=62;i++)if(b[i])return b[i];return 0;
}
求异或第K小值

求异或第K小值,在求得的线性基的基础上需要进行重构,使得线性基每个元素最高位的1,所在的那一位,只有这个元素在这一位的数字为1,其余元素在这一位的数字为0。例如原来的线性基:
p 3 = 10010011 p3 = 10010011 p3=10010011
p 2 = 00101000 p2 = 00101000 p2=00101000
p 1 = 00010111 p1 = 00010111 p1=00010111
p 0 = 00000010 p0 = 00000010 p0=00000010
重构成为:
p 3 = 10000100 p3 = 10000100 p3=10000100
p 2 = 00101000 p2 = 00101000 p2=00101000
p 1 = 00010101 p1 = 00010101 p1=00010101
p 0 = 00000010 p0 = 00000010 p0=00000010
也就是说,某一位至多只有一个元素能影响。
重构后得到的 p p p 数组, p i p_i pi​对于异或值结果的贡献为 2 i 2^i 2i,如果我要求异或值第10小,相当于求 p 3 ⊕ p 1 p_3 \oplus p_1 p3​⊕p1​。因为 10 = 2 3 + 2 1 10=2^3+2^1 10=23+21

void rebuild()        //对b[]重构
{for(int i=62;i>=1;i--){if(b[i])          //有第i位为1的数字 {for(int j=i-1;j>=0;j--){if(b[i]&(1ll<<j))b[i] ^= b[j];}}}for(int i=0;i<=62;i++)      //得到p[]数组if(b[i])p[cnt++] = b[i];
}
ll Kth(ll k)          //求异或值第K小
{if(flag)k--;if(k==0)return 0;ll res = 0;if(k>=(1ll<<cnt))         //不存在第K小return -1;for(int i=0;i<cnt;i++){if(k&(1ll<<i))        //k有这一位,则这一位的p[i]产生了贡献res ^= p[i]; }return res;
}
判断一个数是否能被数组元素异或得到

根据线性基的插入性质,如果一个数字可以插入到数组的线性基中,那么这个数字一定不能被原数组异或得到,反之则能。

一个数字无法插入线性基,则其一定是异或若干个数之后变成了0。
那么就能得到: x ⊕ a k 1 ⊕ a k 2 . . . . . . . = 0 x \oplus a_{k1} \oplus a_{k2}.......=0 x⊕ak1​⊕ak2​.......=0
所以: a k 1 ⊕ a k 2 ⊕ . . . . . . . = x a_{k1} \oplus a_{k2} \oplus .......=x ak1​⊕ak2​⊕.......=x
所以,如果 x x x不能成功插入线性基,一定是因为当前线性基里面的一些数异或起来可以等于 x x x。

代码将插入代码稍加修改即可。

例题:

模板(求异或最大值): 洛谷P3812 【模板】线性基.

求异或第K小值: 杭电3949 XOR.

一点思维:洛谷P3857 [TJOI2008]彩灯.

[数学]------线性基相关推荐

  1. 【清华集训2014】玛里苟斯(数学 线性基)

    original link - http://uoj.ac/problem/36 题意: 有一个多重集S={a1,a2,...an}S=\{a_1,a_2,...a_n\}S={a1​,a2​,... ...

  2. 【基础操作】线性基详解

    线性基是一个奇妙的集合(我摘的原话) 这里以非 $OI$ 的角度介绍了线性基 基础部分 模板题 给你 $n$ 个数的集合,让你选出任意多个不重复的数,使得它们的异或和最大. 线性基是什么 我们称集合 ...

  3. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

  4. BZOJ4568: [Scoi2016]幸运数字(线性基 倍增)

    题意 题目链接 Sol 线性基是可以合并的 倍增维护一下 然后就做完了?? 喵喵喵? // luogu-judger-enable-o2 #include<bits/stdc++.h> # ...

  5. HDU3949(线性基算法模版)

    题意:给出N个数,再给出q次查询,每一次的查询在N个数中的值进行异或后第k小的值是多少! 这个线性基我也今天刚学,也只是在套模版,有些地方感觉有点难理解! #include<iostream&g ...

  6. 线性基+树上倍增 ---- BZOJ4568[线性基+树上倍增]

    题目链接 题目大意:就是给你一棵树,每个树上的节点都有一个权值,现在给你一个询问u和v问你这个路径上面挑任意几个数进行xor运算,问你xor最大值是多少 解题思路:对于每个点我们可以维护它向根节点上面 ...

  7. Luogu P5556 圣剑护符(线性基,树链剖分,线段树)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Problem 小L 和 小K 面前的圣剑由 nnn 块护符组成,分别编号为 1,2,-,n1,2,\ ...

  8. HDU3949 XOR (线性基、查找第k小值)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 我们用高斯消元求出的a1,a2,-,ana_1,a_2, \dots,a_na1​,a2​,-,an​ ...

  9. 2017年ICPC西安邀请赛A、XOR(线段树套线性基 + 思维)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目传送门 Problem 给你 nnn 和 nnn 个整数的数组 aaa,以及kkk和qqq,有 q ...

最新文章

  1. JDK8:Lambda表达式操作List集合
  2. shell 脚本 文件夹扫描获取文件
  3. git 给每个branch设置权限_自定义git命令阅读开源项目
  4. DataGridView控件60招(一)
  5. 【机器学习】Apriori 算法进行关联分析和FP-growth算法
  6. 数据结构——树与二叉树
  7. 南通大学python期末考试试卷答案_南通大学2015-2016年1学期《软工》作业点评总结...
  8. 服务器上的Linux中Tomcat有时会挂掉的问题及方法
  9. 二、WIN10 64位下Pycharm打包.py程序为可执行文件exe
  10. c++批量重命名_手把手教你用Python批量给图片添加水印 | 知了干货分享
  11. oracle数据表空间与数据文件,oracle 操作表空间和数据文件
  12. echarts判断x轴是否展示的全_vue+echart前端可视化操作(装X必备)
  13. 【MySQL】MySQL的帮助文档
  14. zabbix 调用api 批量删除主机
  15. ros control
  16. Silverlight获取子控件和父控件方法
  17. 微信小程序云开发教程-微信小程序的JS基础-this关键字
  18. 软考信息系统项目管理师真题及答案之案例分析
  19. 免费音效素材,拿走不谢。
  20. 无密码解锁iPhone

热门文章

  1. MBProgressHUD自定义Loading图片
  2. Android O Working With Fonts
  3. MySQL查看表结构方法整理
  4. 「题解」老鼠与猫的交易
  5. Centos8出现”糟糕!有些地方出问题了“(A problem has occured and zhe system cant recover),循环登出的错误解决方案
  6. 自动化测试面试题及答案
  7. 开通淘宝个人店铺要点之验证支付宝信息!
  8. steam vr 手柄的交互
  9. 惠租车挪威租车旅游攻略
  10. selenium python高级教程_自动化测试系列 python+selenium的使用教程(一)