线性基
Posted 66t6
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性基相关的知识,希望对你有一定的参考价值。
线性基
概述
线性基,是一个线性空间(二元运算为异或)的极大线性无关子集
用于解决一系列集合异或和最值问题
注意与Trie树区别在于可以多个
性质
1.表示任意一个异或和方式唯一
2.所有子集异或和不为0
3.线性基内高位各不相同
4.(tot)个位置可以表示(2^{tot})种异或和
实现
先做一些定义
(p_i)表示以第(i)位为最高位的基底
(dig_i)表示从低到高第(i)个有值的位置
插入
从高到低考虑(x)的每一位(其实是当前的最高位)
若这一位(p)没有值直接插入
否则异或上这一位的(p)
那么这一位以上的位均会变成0,并且如果他能插入应为线性无关的因此保证可正确性
操作直到成功插入或(x=1)后停止(线性有关)
inline char Insert(re ll x){re int i;for(i=DIGIT;x;--i)if((x>>i)&1){if(p[i])x^=p[i];else return p[i]=x,1;}return 0;}
求子集最大/最小异或和
对最大:从高向低位贪心(线性基性质导致低位不会影响高位)能拼凑出当前位就拼
对最小:这个直接找到最高位最低的基即可
inline ll Find_max(void){
re int i;re ll res=0;
for(i=DIGIT;~i;--i)if((res^p[i])>res)res^=p[i];
return res;
}
inline ll Find_min(void){
re int i;re ll res=0;
for(i=0;i<=DIGIT;++i)if(p[i])return p[i];
}
高斯消元
把线性基化成每一个向量最多含一位的形式
方便比较
去重第k小
直接二进制拆位后拼凑即可
这是不用(dig)预处理的(同理)
inline ll Find_kth(re ll k){
re int i,x;
if(n^tot)--k;if(k>=(1ll<<tot))return -1;
ans=0,x=tot;for(i=DIGIT;~i;--i)if(p[i])if(((k>>(--x))&1)^((ans>>i)&1))ans^=p[i];
return ans;
}
以上是关于线性基的主要内容,如果未能解决你的问题,请参考以下文章