【线性基】

【线性基】

与异或和有关的问题: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;

致谢

https://www.luogu.com.cn/article/zo12e4s5

posted @ 2026-02-08 22:28  White_ink  阅读(8)  评论(0)    收藏  举报