一、概念
线性基实际上就是维护了一个数组 \(p\),满足 \(p_i\) 在二进制下的最高位为第 \(i\) 位。
二、实现
现在我们有一个数组 \(a\),我们要构造他的线性基 \(p\)。
每次插入 \(a_i\) 时,我们都从高位往低位遍历,用以寻找第一个空位插入它。当然,我们也不能直接把原数插入。为了方便查询是否存在该数,每次到达 \(a_i\) 最高位但是 \(p_j\) 已经有值时,\(a_i\gets a_i\oplus p_j\) 。
时间复杂度 \(O(n\log V)\)。
void add(int x){for(int i=52;~i;i--)if(x&(1ll<<i)){if(p[i]) x^=p[i];else return p[i]=x,void();}
}
三、应用
- 查询当前插入的数值是否能够异或出 \(x\)。
实际上我们可以理解为插入 \(x\),能插得进去就说明不能,否则就是可以。
int check(int x){for(int i=52;~i;i--){if((x&(1ll<<i))==0) continue;if(p[i]) x^=p[i];else return 0;}return 1;
}
- 查询当前数能凑出的异或最大值 \(/\) 最小值。
最小值就是从小往大枚举第一个 \(>0\) 的 \(p_i\)(都为 \(0\) 的话最小值就是 \(0\)),最大值从大往小枚举,假如异或 \(p_i\) 后 \(ans\) 更大,那么 \(ans\gets ans\oplus p_i\)。
int maxn(){int ans=0;for(int i=52;~i;i--)ans=max(ans,ans^p[i]);return ans;
}int minn(){for(int i=0;i<53;i++)if(p[i]) return p[i];return 0;
}
当然,线性基也可以辅助其他算法或思想(如贪心)使用。