不得不说,线性基是一个神奇的东西
它维护的东西与“异或”密切相关
题意:
给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大。
当然,也可以最小,甚至,可以求任意异或和第k大!(哇,好niubi)
a[i]表示当前线性基内任意异或出来的数字中,最高位为i的任意一个数字。
从高位到低位枚举所有位数,如果x的第i位有值:如果a[i]不存在,则a[i]=x,并退出。
如果a[i]存在,令x^=a[i]。如果最后x变成了0,那么说明x在线性基内。
inline bool insert(int x) { for(int i=nmr;i>=0;i--) { if(x&(1LL<<i)) { if(a[i]==0) { a[i]=x; break; } x^=a[i]; } } return x>0; }
从高位到低位扫描线性基。如果异或之后答案变大,就把这一位异或到答案。
inline int get_max() { int ans=0; for(int i=nmr;i>=0;i--) { if((ans^a[i])>ans) ans^=a[i]; } return ans; }
查询最小值
从低位到高位扫描线性基。最低位上的线性基即为答案。
inline int get_min() { for(int i=0;i<=nmr;i++) if(a[i]>0) return a[i]; }
首先我们要改造一下线性基。我们把线性基改造成每一位相互独立,意思就是对于第i位,
线性基上只有第i位可能是1。(其它位是1就不相互独立了(互相异或不对了))具体如何改造,就是从高位向低位扫描,
对于第i位线性基a[i],对于j<i,如果a[i]的第j位是1,就让a[j]异或上a[i]。
查询的时候,将k进行二进制拆分,对于的1位,就异或对应的线性基。
最终得到的答案是第k小值。
inline void rebuild() { cnt=0; for(int i=nmr;i>=0;i--) { for(int j=i-1;j>=0;j--) if(a[i]&(1LL<<j)) a[i]^=a[j]; } for(int i=0;i<=nmr;i++) if(a[i]) p[cnt++]=a[i]; } inline int query(int k) { int ans=0; if(k>=(1LL<<cnt)) return -1; for(int i=nmr;i>=0;i--) { if(k&(1LL<<i)) ans^=p[i]; } return ans; }
so
线性基码量小,而且速度快(遇到异或问题可以想到线性基666)
基于本题:只要查询最大值即可,这里给出全代码
#include<cstdio> #include<iostream> #include<cstring> using namespace std; #define olinr return #define nmr 60 #define love_nmr 0 #define int long long int a[nmr]; int cnt; int n; int x; int p[nmr]; inline bool insert(int x) { for(int i=nmr;i>=0;i--) { if(x&(1LL<<i)) { if(a[i]==0) { a[i]=x; break; } x^=a[i]; } } return x>0; } inline int get_max() { int ans=0; for(int i=nmr;i>=0;i--) { if((ans^a[i])>ans) ans^=a[i]; } return ans; } inline int get_min() { for(int i=0;i<=nmr;i++) if(a[i]>0) return a[i]; } inline void rebuild() { cnt=0; for(int i=nmr;i>=0;i--) { for(int j=i-1;j>=0;j--) if(a[i]&(1LL<<j)) a[i]^=a[j]; } for(int i=0;i<=nmr;i++) if(a[i]) p[cnt++]=a[i]; } inline int query(int k) { int ans=0; if(k>=(1LL<<cnt)) return -1; for(int i=nmr;i>=0;i--) { if(k&(1LL<<i)) ans^=p[i]; } return ans; } signed main() { ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) { cin>>x; insert(x); } cout<<get_max(); olinr love_nmr; }