线性基
线性基用于解决异或相关的问题。
如何构造线性基?
设 $ p $ 为线性基的集合。
插入一个数 $ x $ 时,枚举其最高位 $ i $ ,若 $ p_i $ 不存在,令 $ p_i = x $ 并退出,否则令 $ x = x : xor : p_x $ 。
void ins(ll x)
{
for(ll i=SIZE-1;i>=0;i--)
{
if(!(x>>i))continue;
if(!p[i]){p[i]=x;break;}
x^=p[i];
}
}
性质 $ 1 $ : 原数列里的任何一个数都可以通过线性基里的数异或表示出来。
性质 $ 2 $ : 线性基没有异或和为 $ 0 $ 的子集。
性质 $ 3 $ : 一个数列的线性基里(可能多个),数的数量一定唯一,且满足性质 $ 1 $ 。
性质 $ 1 $ 显然。
性质 $ 2 $ : 假设存在 $ p_1 \bigoplus p_2 \bigoplus p_3 =0 $ ,则 $ p_1 \bigoplus p_2 = p_3 $ ,故 $ p_3 $ 不会被插入,矛盾。
性质 $ 3 $ : 分类讨论。
$ 1. $ 当所有数都能被插入线性基时,显然成立。
$ 2. $ 若元素 $ x $ 无法插入线性基,则 :
$ ( : 1 : ) $ $ x=0 $ 。肯定无法插入线性基。
$ ( : 2 : ) $ 存在 $ p_a \bigoplus p_b \bigoplus ... \bigoplus p_c =x $ 。就是说插入 $ p_c $ 之后, $ x $ 就必定无法插入了。故 $ x $ 与 $ p_c $ 相排斥,但两者只影响线性基中一位的取值。
综上,性质 $ 3 $ 得证。
查询一个数能否被异或得到
从高位向低位找,若该位为 $ 1 $ 则异或该位的线性基。
由性质 $ 1 $ ,若最后的值为 $ 0 $ ,说明该数能够被表示出来。
bool find(ll x)
{
for(ll i=SIZE-1;i>=0;i--)
if(x>>i)x^=p[i];
return !x;
}
查询异或最大值
按位贪心。若当前答案异或上 $ p_i $ 的值变大,则异或 $ p_i $ 。
ll qmax()
{
ll ans=0;
for(ll i=SIZE-1;i>=0;i--)
ans=max(ans,ans^p[i]);
return ans;
}
查询异或最小值
答案即线性基中的最小元素。
ll qmin()
{
if(flag)return 0;//flag表示是否存在0这个数
for(ll i=0;i<SIZE;i++)
if(p[i])return p[i];
}
求排名和大小以后会补。
前缀线性基板子 CF1100F