这章将好好讲讲线性代数。。[kczno1牛逼
线性组合:对于维向量组和系数,称为其对应的线性组合。
向量空间:对于一个n维向量的集合V,我们称其是一个向量空间,当且仅当V的任意两个向量的任意线性组合仍。
生成空间“对于n维向量组,我们称其生成空间为其所有线性组合组成的集合。
向量空间和生成空间的区别就是字面意思。
前面没听懂的没关系:听懂下面两个定义就好了。
线性相关:对于n维向量组,我们称其为线性相关的,当且仅当他们可以通过不全为的线性组合得到零向量。
线性无关:对于n维向量组,我们称其维线性无关的,当且仅当他们不是线性相关的。【废话
基:对于一个向量空间V,我们称n维向量组是V的一组基,当且仅当a线性无关,而且生成空间为V。
给你n个数,问有多少个数能被这n个数中某几个数异或得到。
含明显我们把这n个数按照二进制高斯消元一下,那么就是答案,左上角那个东西就是a的阶。
给你n个数,m次询问,每次给出一个,问x能否被S的某个子集异或得到;或者加入这个x。
前面那个东西很简单,就直接把x放进原来的数的基扫一遍就可以。
后面那个东西也是很容易实现的,假若可以被前面的某个自己异或得到那么就直接忽略,因为插不插入无所谓。
否则就把x插入最高位的那个位置。
一个集合S,初始为空,m次操作,
每次操作要么给出一个x,问x能否被S的某个子集异或得到;
要么给出给出一个x,往S加入这个x。要么给出一个x,删除S中的x。
其实这个分两种做法:
如果可以离线:我们每个基向量记录一下它的删除时间【这个删除时间指的是插入时初始的x的删除时间】。
那么当我们将x插入的时候比较如果x的当前位为1,那么我们比较一下x的删除时间和当前为值的基变量的删除时间。
如果x的删除时间大于当前位置的删除时间,那么就把两者交换,继续拿新的x往下做操作。
考虑证明这个东西为什么是对的。
可以看到,与x比较删除时间的那些位置在被遍历过之后的删除时间肯定时单调不上升的。
而假如要判断的x要经过这个基向量,如果那个基向量的删除时间<当前时间,那么这一位就一定不存在一个>=当前时间的基向量存在
所以我们判断一个东西是否在线性空间的时候,我们可以遍历那些删除时间>=当前时间的基向量就好了。
那么复杂度就是【小括号写不出来,就不打渐进了
如果要求强制在线:实际上线性基是支持删除的。
对于每一个基向量和零向量都保存它是由哪些向量异或得到的。
当删除向量x时,查找零向量中是否存在包含x的,如果有包含x的零向量,那么说明x能被其它向量异或得到的。对线性基没有影响。
否则的话,我们找到基向量里位最低的包含x的,将它所保存的信息异或到其他包含x的基向量里面就好了。
这个信息包括了是由那些向量异或得到的和向量本身。
时间复杂度:,其中Y为插入总数。空间就很显然了
下面面又是几个定义
sgn表示的是,表示的是p这个排列的逆序对个数。
行列式的集合意义是n维平行体的有向体积。求矩阵的多项式可以用来图的生成树总数。具体可以看我的Matrix
接着我们再讲另一个东西:
特征多项式:对于一个n阶方阵A,如果存在标量和非零向量v,使得,则称为A的一个特征值,v为A的一个特征向量。
如何理解这条等式呢?首先v是一个列向量,w你可以把它看成一个值,那么一个矩阵乘上一个列向量还是等于一个列向量。w这个值乘上v这列向量还是等于一个列向量。
那么我们考虑一个w,如果它是A的一个特征值,那么存在非零解。
也就是说有非零解。
这个矩阵乘向量的形式像一个线性齐次方程组的形式,当时,v有非零解。
所以,那么。
我们把这个标量看成一个变量x,那么就是一个多项式,明显我们将特征值带进这个多项式的时候,结果为0。那么这个多项式就被我们称为特征多项式。
同时,我们不仅可以将值代进这个多项式,我们还可以将矩阵代入这个多项式。
特别的,如果我们将原矩阵A代入这个多项式,得到的是0矩阵。【老师也不会证,当作结论记下,这个在比赛中很有用。
这个是哈密尔顿–凯莱定理。
注意!本篇文章注意区分插入和填入。
这个神奇的数据结构在很早之前就会了,现在写博客回忆一下。
线性基有着非常好的性质,它主要是用来解决异或和之类的问题。
他是一个什么样子的东西呢?
首先他是一个数组,是一个那么大的数组。它存些什么呢?
我们在这里假设就是线性基。
有两种取值,第一种就是空;第二种是二进制最高位为i的任意数的异或和。
先等等,这样直接说好像没有什么意义。
不如我们先探求一下它的性质,再想着如何去维护?
性质1:线性基中的数可以异或出原数组。
性质2:线性基第i个的二进制最高位为i。
接下来,我们来研究怎么保证这两个性质。
插入?
假设插入的数是,那么我们找到x的二进制最高位,如果线性基的第个数为空,那么直接填进去。
否则,我们就异或上线性基中的第个数,那么可以保证x的最高位肯定小于i了。
继续往下找。
很明显可以保证线性基的性质,如果最后没有填进去,那么说明线性基中的数已经可以组成x了。
代码<略丑>
void insert(long long*now,long long c){
for(int i=60;i>=0;i--)
if(c>>i){
if(now[i]) c^=now[i];
else {now[i]=c;break;}
}
}
不好意思线性基不支持删除,因为具有后效性;遇到支持删除的线性基,尽量倒过来构造(从后往前)。
我们很明显可以想到一种贪心,拿一个ans从线性基中的高位往低位扫,如果异或上当前的数可以使得答案变大,那么我们就异或上它。否则就不异或。
证明也是极其简单的。(因为根据性质一,线性基中的数可以异或出原数组,所以原数组可以异或得到的,线性基也可以异或得到。
for(int q=60;q>=0;q--) ans=max(ans,ans^now[q]);
分两种情况讨论。
1.线性基中的数的个数等于原数组中的数的个数,说明,每个数都填入了一个位置,输出线性基中非空最低位的数即可。
2.否则,一定有数没有填入,说明,当前这个数可以被 未插入这个数的线性基组成,他们两个异或起来等于0.最小为0.
首先n个数建一个线性基,看一下这个数能否填入线性基中,如果可以,那么就不能被n个数异或得到,否则可以。
首先我们可以做一点事情使得线性基拥有美好的性质。
我们尽量让这一位只有i这位为1。
怎么做到?我们寻找二进制第二高位的j,然后让,就可以消掉j这位,继续往下消,直到消到最小。
首先,线性基的正确性是显然的。
如果为空呢?
那么我们至少保证了为空。(没问题啊。。。
第k小,我们把k二进制拆分,如果第i位为1,那么就异或上线性基中非空的第i位。
思考怎么证明。第i个数如果非空,那么肯定拥有唯一的第i位,因为上面的都被异或掉了,下面的本来就没有。
所以不管怎么异或, 如果线性基中第i个数是非空的,肯定只有这个数控制着第i位,所以就相当于非空的线性基组成二进制数一样,异或起来就行了。
注意判断是否存在0对答案的影响
void prepare(now){
for(int i=60;i>=0;i--)
for(int j=i;j>=0;j--)
if(now[i]>>j) now[i]^=now[j];
}
int find_kth(long long k){
prepare(now);
int t=0,d[65];//t记录有多少个非空的数位,d[i]表示第i个非空数位是哪一个
for(int i=0;i<=60;i--)
if(now[i]) d[t]=i,t++;
if(t=0;i--)//d的范围是[0,t)
if(k>>i){//第i位为1,那么就异或上有数的第i位
ans^=now[d[i]];
k^=(1<