发现了线性基的一些性质和用法
线性基合并
直接把另一个暴力插入。
可以判一下如果满了就不插入,剪枝很有作用
一定要满足从高位到低位贪心
struct Data{
int a[32];
bool flag;
Data(){ memset(a,0,sizeof(a)); flag = 0; }
Data operator + (Data z){
Data res = z;
if ( z.flag ) return res;
if ( flag ) return *this;
for (int i = 30 ; i >= 0 ; i--){
int x = a[i];
for (int j = 30 ; j >= 0 ; j--){
if ( x >> j & 1 ){
if ( !(res.a[j] >> j & 1) ){ res.a[j] = x; break; }
x ^= res.a[j];
}
}
}
res.flag = 1;
for (int i = 29 ; i >= 0 ; i--){
res.flag &= (res.a[i] >> i) & 1;
if ( res.a[30] >> i & 1 ){
res.a[30] ^= res.a[i];
}
}
return res;
}
void insert(int x){
for (int j = 29 ; j >= 0 ; j--){
if ( x >> j & 1 ){
if ( !(a[j] >> j & 1) ){ a[j] = x; break; }
x ^= a[j];
}
}
}
};
线性基的性质
如果把线性基定义为所有元素一定是一个线性无关组
有如下性质
1.设线性基的异或集合中不存在00。
2.线性基的异或集合中每个元素的异或方案唯一,其实这个跟性质1是等价的。
3.线性基二进制最高位互不相同。
4.如果线性基是满的,它的异或集合为[1,2n−1][1,2n−1]。
5.线性基中元素互相异或,异或集合不变。
那么可以查询能够组合出来的数的最小值、k大值
k大值查询
线性基要维护成有主元的位,只有主元是1,没有主元的位显然不会影响答案
那么,直接贪心即可。选择第i个主元相当于排名上升2i-1
一些技巧
hdu 6579 , 2019 Multi-University Training Contest 1 - B operation
求区间选一些数的抑或最大值。在后面动态加入,强制在线。要求复杂度 O ( n l o g n ) O(nlogn) O(nlogn)不需要维护区间线性基,我们只需要贪心的维护,使得线性基高位的数的位置尽量靠右。这样高位更可能被选到
以前更早加入的数被重复的往下替换
相当于是时间戳线性基。(有点像维护连通性的时间最大生成树)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 20;
struct Data{
int a[32],id[32];
bool flag;
Data(){ memset(a,0,sizeof(a)); memset(id,0,sizeof(id)); flag = 0; }
void insert(int x,int curid){
for (int j = 29 ; j >= 0 ; j--){
if ( (x >> j) & 1 ){
if ( !(a[j] >> j & 1) ) { a[j] = x , id[j] = curid; break; }
else if ( id[j] < curid ){
swap(id[j],curid);
swap(a[j],x);
}
x ^= a[j];
}
}
}
int query(int curid){
int res = 0;
for (int j = 29 ; j >= 0 ; j--){
if ( !((res >> j) & 1) ){
if ( id[j] >= curid ) res ^= a[j];
}
}
return res;
}
}base[maxn];
int n,m,a[maxn];
int main(){
int cases;
scanf("%d",&cases);
while ( cases-- ){
scanf("%d %d",&n,&m);
for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]);
for (int i = 1 ; i <= n ; i++){
base[i] = base[i - 1];
base[i].insert(a[i],i);
}
int lastans = 0;
for (int i = 1 ; i <= m ; i++){
int tp,l,r,x;
scanf("%d",&tp);
if (tp == 0 ){
scanf("%d %d",&l,&r);
l = (l ^ lastans) % n + 1 , r = (r ^ lastans) % n + 1;
if ( l > r ) swap(l,r);
lastans = base[r].query(l);
printf("%d\n",lastans);
}else{
scanf("%d",&x);
x = (x ^ lastans);
n++;
base[n] = base[n - 1];
base[n].insert(x,n);
}
}
}
}