线性基入门

推荐博客 : https://www.cnblogs.com/vb4896/p/6149022.html

      https://blog.csdn.net/qaq__qaq/article/details/53812883

这个我觉得不是很好理解,花了一天半得时间,稍微懂了一点,写个博客

 

首先我们要明确这个线性基可以解决什么样得问题,例如动态增加元素,求解集合异或最大值

这里有一个增加操作,向里面增加一个元素,从最高位向下扫,当扫到 1 ,并且线性基中该位置为 0 ,则将这个元素加入到线性基中,否则用此元素去异或线性基中的数

int val[maxn][40];
void insert(int b[], int x){
    for(int i = 30; i >= 0; i--){
        if (x>>i&1){
            if (!b[i]) {b[i] = x; break;}
            else x ^= b[i];
        }
    }
}

 

 合并

void unit(int x,int y){
    // 将 x 暴力插入到 y 中 
    for(int i=30;i>=0;--i)
        if(val[x][i]) insert (val[y],val[x][i]);
}

 查询

查询一个元素是否再集合中x

最大值

从高位到低位去扫一遍

int cal(int p){
    int ans = 0;
    for(int i = 30; i >= 0; i--){
        if ((ans^val[i]) > ans) {
            ans ^= val[i];
        }
    }
    return ans;
}

 最小值

int query(){
    for(int i = 0; i <= 30; i++){
        if (val[i]) return val[i];
    }
    return 0;
}

 求解第K大

将线性基重新构造一下

ll cnt = 0;
ll p[65];

void rbuild(){
    for(ll i = 60; i >= 0; i--){ 
        for(ll j = i-1; j >= 0; j--){
            if ((1ll<<j)&a[i]) a[i] ^= a[j];
        }
    }
    
    for(ll i = 0; i <= 60; i++){
        if (a[i]) p[cnt++] = a[i];
    }
}

ll query(ll x){
    if (x >= (1ll<<cnt)) return -1;
    ll ans = 0;
    for(ll j = 60; j >= 0; j--){
        if ((1ll<<j)&x){
            ans ^= p[j];
        }
    }
    return ans;
}

 

posted @ 2018-04-27 21:00  楼主好菜啊  阅读(117)  评论(0编辑  收藏  举报