线性基入门
推荐博客 : 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; }
东北日出西边雨 道是无情却有情