线性基

刚刚学习了线性基,网上那些什么线性空间之类的概念我没有细看,感觉就像是个贪心+构造。
对于一个集合\(S\),它的异或线性基就是其中一些数组成的的集合\(S'(S'\subset S)\),满足\(S'\)中的任意多个数异或出来的值的集合等于\(S\)中的任意多个数异或出来的值的集合。线性基的的构造方法如下:
首先有一个每项值都为\(0\)的数组\(basis\),依次枚举\(S\)中的数(记为\(x\)),在二进制下从高到低遍历\(x\)的每一位,如果这一位为\(1\),且\(basis\)对应的这一位还没有值,就将其赋值为\(x\)并停止遍历,否则将\(x\)异或上\(basis[bit]\)并遍历下一位。这样的话,代码就长成下面这样了:

void insert(ll x) {
    for(ll i = 62; i >= 0; --i) { //从高到低枚举每一位
        if((x>>i)&1) { //当前位为1
            if(!basis[i]) { //basis对应的位未赋值
                basis[i] = x;
                break;
            }
            x ^= basis[i];
        }
    }
}

查询的话其实差不多,也是从高到低遍历\(x\)在二进制下的每一位,若这一位为\(1\),就把\(x\)异或上\(basis\)对应的这一位的值。这个过程中如果\(x\)变成\(0\),表明\(x\)可以被异或出来,否则就不行。代码:

bool query(ll x) {
    //特判0(代码省略)
    for(ll i = BIT; i >= 0; --i) {
        if((x>>i)&1) x ^= b[i];
        if(!x) return true;
    }
    return false;
}

有了上面的知识我们就可以做这道题了!
AC代码:

#include <bits/stdc++.h>

using namespace std;

#define N 1005
#define ll long long

namespace Linear_Basis {
    #define BIT 62
    ll b[BIT+1];
    void insert(ll x) {
        for(ll i = BIT; i >= 0; --i) {
            if((x>>i)&1) {
                if(!b[i]) {
                    b[i] = x;
                    break;
                }
                x ^= b[i];
            }
        }
    }
    bool query(ll x) {
        for(ll i = BIT; i >= 0; --i) {
            if((x>>i)&1) x ^= b[i];
            if(!x) return true;
        }
        return false;
    }
}
using namespace Linear_Basis;

int n, ans;
pair<ll, int> a[N];

int main() {
    cin >> n;
    for(int i = 1; i <= n; ++i) cin >> a[i].first >> a[i].second;
    sort(a+1, a+n+1, [](const pair<long long, int> &__x, const pair<long long, int> &__y) {
        return __x.second > __y.second;
    });
    for(int i = 1; i <= n; ++i) {
        if(query(a[i].first)) continue;
        else insert(a[i].first), ans += a[i].second;
    }
    cout << ans;
    return 0;
}
posted @ 2018-10-22 17:53  dummyummy  阅读(248)  评论(0编辑  收藏  举报