【线性基】
【线性基】
与异或和有关的问题:01Trie、异或线性基
板子
struct LB { // Linear Basis
const int BASE = 63;
vector<i64> d, p;
int cnt, flag;
LB() {
d.resize(BASE + 1);
p.resize(BASE + 1);
cnt = flag = 0;
}
bool insert(i64 val) {
for (int i = BASE - 1; i >= 0; i--) {
if (val & (1ll << i)) {
if (!d[i]) {
d[i] = val;
return true;
}
val ^= d[i];
}
}
flag = 1; //可以异或出0
return false;
}
bool check(i64 val) { // 判断 val 是否能被异或得到
for (int i = BASE - 1; i >= 0; i--) {
if (val & (1ll << i)) {
if (!d[i]) {
return false;
}
val ^= d[i];
}
}
return true;
}
i64 ask_max() {
i64 res = 0;
for (int i = BASE - 1; i >= 0; i--) {
if ((res ^ d[i]) > res) res ^= d[i];
}
return res;
}
i64 ask_min() {
if (flag) return 0; // 特判 0
for (int i = 0; i <= BASE - 1; i++) {
if (d[i]) return d[i];
}
}
void rebuild() { // 第k小值独立预处理
for (int i = BASE - 1; i >= 0; i--) {
for (int j = i - 1; j >= 0; j--) {
if (d[i] & (1ll << j)) d[i] ^= d[j];
}
}
for (int i = 0; i <= BASE - 1; i++) {
if (d[i]) p[cnt++] = d[i];
}
}
i64 kthquery(i64 k) { // 查询能被异或得到的第 k 小值, 如不存在则返回 -1
if (flag) k--; // 特判 0, 如果不需要 0, 直接删去
if (!k) return 0;
i64 res = 0;
if (k >= (1ll << cnt)) return -1;
for (int i = BASE - 1; i >= 0; i--) {
if (k & (1LL << i)) res ^= p[i];
}
return res;
}
void Merge(const LB &b) { // 合并两个线性基
for (int i = BASE - 1; i >= 0; i--) {
if (b.d[i]) {
insert(b.d[i]);
}
}
}
};
常见模型
n个数中取k个数,求异或和最大值
线性基+DP
(1)把n个数全部插入线性基
(2)构造dp[k]:恰好选i个数时异或和的最小值
初始化极小值,dp[0]=0
(3)遍历每个线性基(0-63),对非0基做01背包
LB lb;
for(int i=1;i<=n;i++) lb.insert(a[i]);
vector<i64> dp(k+1,-inf_i64);
dp[0]=0;
for(int i=0;i<lb.BASE;i++){
i64 b=lb.d[i];
if(b==0) continue;
for(int j=k;j>=1;j--){
if(dp[j-1]!=-inf_i64){
dp[j]=whink_max<i64>(dp[j],dp[j-1]^b);
}
}
}
cout<<dp[k]<<endl;

浙公网安备 33010602011771号