【算法笔记+SGU275+HDU3949】线性基(XOR,求n个数异或得到的第k小的数)
网上大佬写的博客。。。我以为自己看懂了(假装看懂)。。。结果第二题就被卡住了。。。看不懂了。。
https://blog.sengxian.com/algorithms/linear-basis
https://www.cnblogs.com/vb4896/p/6149022.html
是我水平不够,看起来有点费劲(;´༎ຶД༎ຶ`)智商堪忧
还是视频看起来轻松很多:青涩的讲解,但是能听懂,给up主点赞!
目前的理解:线性基就是通过异或构建行阶梯矩阵,找到最大线性无关的向量组,去解决有关XOR的一些问题
数x对应的二进制为: bj=0或者1,用p[]存下面矩阵中的数
所谓线性基,就是线性代数里面的概念。一组线性无关的向量便可以作为一组基底,张起一个线性的向量空间,这个基地又称之为线性基。
第一个例子:
,插入的时候从高位向低位看起
--->插入a[0]=7=0111:a[0]的=0,p[2]=a[0]
矩阵:
--->插入a[1]=2=0010:a[1]的=1,p[1]=a[1],后面的位k,若,那么p[1]^=p[k](p[k]的),消掉p[1]中后的1,让p[1]中只有=1;同理,p[1]上面的行j,如果p[j]中的=1,那么p[j]^=p[1],消掉p[j]中位上的1,保证p[j]中只有
矩阵:
--->插入a[2]=3=0011,从高位向低位看起,因为=1的位置已经存入数a[1]了,所以为了保证我们要构建的是行阶梯矩阵,a[2]^=p[1],新的a[2]=0001,其中,p[0]=a[2],和插入a[1]时相同的做法,用下面的行消去自己,用自己消去上面的行中不应该为1的1:
矩阵:
--->插入a[3]=4=0100,,但是p[2]已经存入数了,a[3]^=p[2]=0,无法插入
至此,线性基对应的行阶梯矩阵已经构建完了,此外,通过构建过程可以知道最终的矩阵可以转化为如下内容:
p[2]、p[1]、p[0]都不为0,所以线性基的大小为num=3,a[4]中n=4,num<n
p[2]、p[1]、p[0]对应的向量是一个最大线性无关的向量组,因为num<n所以a[]中的数可以通过异或得到0,这点可以通过插入a[3]时出现0得到验证。当num=n时,这n个向量组成最大线性无关的向量组,根据线性无关的定义可以知道只有这些向量前面的系数都为0时才可以得到0。
注意:这里的p[2]、p[1]、p[0]进行异或相当于其对应的向量进行加法运算(二进制加法,没有进位)。
用新的数组L(或者一个vector<>)存不为0的p[i],若求a[4]所能构成的异或的数中的第k小,k=,新的矩阵有如下对应关系:
若求第k=1小,因为num!=n,所以可以异或出0,那么可异或出第1小的数就是0
若求第k=4小,因为num!=n,所以可以异或出0,所以k=k-1=3=0011,,那么可异或出第1小的数就是L[0]^L[1]等价于
第二个例子:
--->插入a[0]=9=1001,p[3]=a[3]
矩阵:
--->插入a[1]=11=1011,p[3]已经有数了,a[1]^=p[3]=0010,p[1]=a[1],用下面的行消自己,用自己消下面的行(但都莫得消)
矩阵:
--->插入a[2]=5=0101,p[2]=a[2],用下面的行消自己,用自己消下面的行(但都莫得消)
矩阵:
最终的矩阵相当于:其中线性基的大小num=3,n=3
用新的数组L存不为0的p[i],求a[3]能异或成的第k小,k=:,对应关系如下:
因为线性基大小num=n,所以不能异或出0
若k=1=0001,,所以第1小的数就是L[0]
若k=5=1001,,所以第5小的数就是L[0]^L[3]
综上所述:
构建行阶梯矩阵时,若a[i]=,从高位往地位第一个为1的位是j,若p[j]已经存入数了,那么a[i]^=p[j],否则直接p[j]=a[i]
在p[j]插入a[i]后,让p[j]下面的行消去p[j]中j位后面的1,让p[j]消去p[j]上面的行中j位上的1,目的是为了尽量使p[j]中只有j位是1
若n个数构成的线性基的大小num=n,则对应的行阶梯矩阵的秩=n,这n个向量线性无关,那么这个n个数不能通过异或得到0,否则可以得到0
在求n个数通过异或构成的第k小的数时,用新的数组L(或者 vector<>)存那些不为0的p[i]
num==n,不能得到0,第k小的数就是k的二进制位上为1的位所对应的L[]值,比如K=1001,那么结果就是L[0]^L[3]
num!=n,不能得到0,k=k-1,结果就是k的二进制位上为1的位所对应的L[]值
num==n时,这个n个数最多能构成-1个不同的数;否则可以构成个不同的数
L[i]^L[j]或者p[i]^p[j] 其实就是a[]上的一些数在异或,只不过目前我们不关心是哪些数在异或(当然也可以通过记录得知),我们只在意能异或成的数的大小
求n个数能构成的最大值,就直接把L[]中的值都异或起来就OK啦!
终于写完原理了٩(˃̶͈̀௰˂̶͈́)و总算是懂了线性基了☆〜(ゝ。∂)
一般1≤a[i]≤1e18,最多60位,所以max_base设成60,p[max_base+3],max_base别设置太大了,可能结果会错,我试过(´・Д・)」,就60吧!
模版:
hdoj3949
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+5;
const int max_base=60;
ll t,n,q,x;
ll a[maxn],p[maxn+3];
vector<ll> v;
void solve()
{v.clear();//清空啊啊啊!!!memset(p,0,sizeof(p));//初始化啊啊啊!!!for(int i=0;i<n;i++){for(int j=max_base;j>=0;j--)//从高位向低位{if(a[i]>>j==0) continue;//该位上为0,对线性基这位没有有贡献if(!p[j])//该行没数,直接填入{p[j]=a[i];for(int k=j-1;k>=0;k--)if(p[k] && p[j]>>k&1)p[j]^=p[k];//下面的行消自己for(int k=j+1;k<=max_base;k++)if(p[k]>>j&1)p[k]^=p[j];//自己消上面的行break;//填入之后结束每一位上的遍历}elsea[i]^=p[j];//该行已经有数}}for(int i=0;i<=max_base;i++)if(p[i])v.push_back(p[i]);}
ll query(ll x)
{if(v.size()!=n) x--;if(x==0) return 0;//能得到0,第1小的数是0if(x>=(1LL<<v.size())) return -1;//能得到0,x已经-1了,x最多达到2^v.size()-1;不能得到0,x最多就是v.size()-1ll ans=0;for(int i=0;i<=max_base;i++)if(x>>i&1)ans^=v[i];return ans;
}
int main()
{//freopen("/Users/zhangkanqi/Desktop/11.txt", "r", stdin);scanf("%lld",&t);for(int i=1;i<=t;i++){printf("Case #%d:\n",i);scanf("%lld",&n);for(int j=0;j<n;j++)scanf("%lld",&a[j]);solve();scanf("%lld",&q);for(int j=0;j<q;j++){scanf("%lld",&x);printf("%lld\n",query(x));}}return 0;
}
SGU275:但是好像没法补题,求n个数异或得到的最大值,直接把非0的p[i]异或起来就完事了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+5;
const int max_base=60;
ll n;
ll a[maxn],p[maxn+3];
void solve()
{for(int i=0;i<n;i++){for(int j=max_base;j>=0;j--)//从高位向低位{if(a[i]>>j==0) continue;//该位上为0,对线性基这位没有有贡献if(!p[j])//该行没数,直接填入{p[j]=a[i];for(int k=j-1;k>=0;k--)if(p[k] && p[j]>>k&1)p[j]^=p[k];//下面的行消自己for(int k=j+1;k<=max_base;k++)if(p[k]>>j&1)p[k]^=p[j];//自己消上面的行break;//填入之后结束每一位上的遍历}elsea[i]^=p[j];//该行已经有数}}
}
int main()
{//freopen("/Users/zhangkanqi/Desktop/11.txt", "r", stdin);ll ans=0;scanf("%lld",&n);for(int i=0;i<n;i++)scanf("%lld",&a[i]);solve();for(int i=0;i<=max_base;i++)if(p[i])ans^=p[i];printf("%lld\n",ans);return 0;
}
【算法笔记+SGU275+HDU3949】线性基(XOR,求n个数异或得到的第k小的数)相关推荐
- hdu 3949(线性基模版) 异或和中第k小的数
传送门 给定 n(n \le 10000)n(n≤10000) 个数 a_1, a_2, \ldots, a_na1,a2,-,an,以及 Q(Q\le 10000)Q(Q≤1000 ...
- hdu3949(线性基,求第k小的异或和
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 XOR Time Limit: 2000/1000 MS (Java/Others) Me ...
- 【CodeForces 1100F】异或线性基 | 贪心 | 离线区间最大异或和 | E
补题ing- 真的不应该错过这场比赛的 qwq 1100F. Ivan and Burgers time limit per test: 3 seconds memory limit per test ...
- 两个有序数组合起来求第k小的数+左老师专访ACM大神(笔记)8月5日斗鱼直播实录
1.长度相等的两个有序数组寻找上中位数 注:上中位数1 2 3 4 5 6为3(偶数两个中位数为前面那个) 思路:去掉不可能为上中位数的,剩下的简化组合求上中位数. 1.1 奇数序列 位置 位置 位置 ...
- python递归算法 电影院票价问题_算法课堂实验报告(二)——python递归和分治(第k小的数,大数乘法问题)...
python实现递归和分治 一.开发环境 开发工具:jupyter notebook 并使用vscode,cmd命令行工具协助编程测试算法,并使用codeblocks辅助编写C++程序 编程语言:py ...
- 第K小的数BFPRT算法
介绍 BFPRT是解决求一个数组中第K小的数的算法,可以时间O(N)的时间复杂度,而使用排序求第K小的数的算法的时间复杂度为O(NlogN),因此BFPRT算法更加高效 思想 (1)分组:将原数组每五 ...
- 分治算法求解列表中第k小的数
分治算法地思想就是将复杂问题分解为简单的子问题,然后寻求子问题的地归结,并组合各个子问题的解一起得到最终复杂问题的解. 针对求解列表中第k小的数,暴力拆解法可以将列表排序然后根据索引求出列表中第k小的 ...
- 算法导论:快速找出无序数组中第k小的数
题目描述: 给定一个无序整数数组,返回这个数组中第k小的数. 解析: 最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1). ...
- java 寻找和为定值的多个数_算法笔记_037:寻找和为定值的两个数(Java)
1 问题描述 输入一个整数数组和一个整数,在数组中查找两个数,满足他们的和正好是输入的那个整数.如果有多对数的和等于输入的整数,输出任意一对即可.例如,如果输入数组[1,2,4,5,7,11,15]和 ...
- 求n个数中的最大或最小k个数
//求n个数中的最小k个数 public static void TestMin(int k, int n) { Random rd = new ...
最新文章
- 京津冀青少年网球分级赛总决赛开打 118名选手对决
- __name__=='__main__'的理解和使用
- 91. 最短Hamilton路径【状压DP】
- powershell如何编程C语言,如何用C语言执行powershell命令
- Rabbit寻宝记(1)
- Ubuntu18.04彻底删除MySQL数据库
- 学习记录-交叉编译环境的设置
- code block怎样实现图形界面_Python 代码实现验证码识别,很稳
- cube一站式云原生机器学习平台-加速分布式任务的运行效率
- 测试管理中的一个问题—功能点覆盖还是功能测试点覆盖
- 怎样制作动图gif?GIF生成器帮你一键制作gif
- 【Axure报错】-Unable to connect to Axure Share. Please make sure you have an internet connection and try
- qt 飞扬青云_Qt编写图片及视频TCP/UDP网络传输
- react devtools插件报错处理
- unbuntu20.0.4 显卡驱动安装,nividia-smi无效
- Android开机启动流程
- 惠普硬盘测试工具_短DST未通过,详细教您惠普笔记本如何检测硬盘
- js 爱心随鼠标移动 产生 并 消散 (源码)
- Oracle中创建和使用触发器Trigger
- FMDB - 数据库操作
热门文章
- C语言实现数字串转数字
- 【SpringBoot_ANNOTATIONS】属性赋值 02 @PropertySource赋值
- ARM开发7.3.4 基础实训( 4 ) 矩阵式键盘的输入系统设计--LPC21XX
- android 文件上传参数,Android OkHttp Post上传文件并且携带参数实例详解
- workbench表头可以是中文_超简单:Python 5步去中国式报表表头
- 外包以小时计算金额的费用_全了!各大税种的计算公式,建议收藏!
- 编写可维护的 JavaScript
- Android动画之补间动画详解
- powershell 模拟IE行为
- WAN killer