参考博客:
https://blog.csdn.net/a_forever_dream/article/details/83654397
https://ouuan.github.io/%E7%BA%BF%E6%80%A7%E5%9F%BA%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/
https://blog.sengxian.com/algorithms/linear-basis
线性基性质:
1、原序列里面的任意一个数都可以由线性基里面的一些数异或得到。
2、线性基里面的任意一些数异或起来都不能得到0 00
3、线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的
解决的问题
1、最大异或和
2、第 kk 大异或和/异或和是第几大
3、求所有异或值的和
【例题】P3812 【模板】线性基
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int M = 70; 5 typedef struct LB{ 6 ll d[M]; 7 void Insert( ll x ){ 8 ll t = x ; 9 for(ll i=62;i>=0;i--){ 10 if( (x & (1ll<<i)) ){ 11 if( d[i] ){ 12 x ^= d[i]; 13 }else { 14 d[i] = x; 15 break; 16 } 17 } 18 } 19 } 20 ll Max(){ 21 ll ans = 0 ; 22 for(int i=62;i>=0;i--){ 23 ans = max( ans , ans ^ d[i] ); 24 } 25 return ans; 26 } 27 }LB; 28 LB s; 29 int n; 30 ll a[M]; 31 int main() 32 { 33 scanf("%d",&n); 34 for(int i=1;i<=n;i++){ 35 scanf("%lld",&a[i]); 36 s.Insert(a[i]); 37 } 38 39 return printf("%lld ",s.Max())*0; 40 }
【例题】P4570 [BJWC2011]元素
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int M = 70; 5 const int N = 1e3+10; 6 typedef struct Node { 7 ll No; 8 ll val; 9 bool operator < ( const Node & rhs) const { 10 return val > rhs.val; 11 } 12 }Node ; 13 Node a[N]; 14 typedef struct LB{ 15 ll d[M]; 16 bool Insert( ll x ){ 17 for(int i=62;i>=0;i--){ 18 if( (1ll<<i) & x ){ 19 if(d[i]){ 20 x ^= d[i]; 21 }else{ 22 d[i] = x ; 23 return true; 24 } 25 } 26 } 27 return false ; 28 } 29 30 }LB; 31 LB s; 32 int n; 33 int main() 34 { 35 scanf("%d",&n); 36 for(int i=1;i<=n;i++){ 37 scanf("%lld%lld",&a[i].No,&a[i].val); 38 } 39 sort( a+1 , a+1+n ); 40 ll ans = 0 ; 41 for(int i=1;i<=n;i++){ 42 if( s.Insert(a[i].No) ) 43 ans += a[i].val; 44 } 45 return printf("%lld ",ans)*0; 46 }
【例题】P3857 [TJOI2008]彩灯
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 100; 5 char s[N][N]; 6 ll a[N]; 7 int n,m; 8 struct LB{ 9 ll d[70]; 10 bool Insert( ll x ){ 11 for(int i=62;i>=0;i--){ 12 if( (x>>i)&1 ){ 13 if(!d[i]){ 14 d[i] = x ; 15 return true; 16 }else{ 17 x ^= d[i] ; 18 } 19 } 20 } 21 return false ; 22 } 23 }S; 24 int main() 25 { 26 scanf("%d%d",&m,&n); 27 for(int i=1;i<=n;i++){ 28 scanf("%s",s[i]); 29 } 30 for(int i=1;i<=n;i++){ 31 32 for(int j=m-1;j>=0;j--){ 33 a[i] = a[i]+ (1ll*(s[i][j]=='O')<<(m-1-j)) ; 34 } 35 //printf("%lld ",a[i]); 36 } 37 int k = 0 ; 38 for(int i=1;i<=n;i++){ 39 if( S.Insert(a[i]) ) 40 k++; 41 } 42 43 ll ans = 1 ; 44 for(int i=1;i<=k;i++){ 45 ans = (ans<<1) % 2008 ; 46 } 47 printf("%lld ",ans); 48 return 0; 49 }
【例题】P3292 [SCOI2016]幸运数字
1 // luogu-judger-enable-o2 2 #include<cstdio> 3 #include<cctype> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 typedef long long ll; 8 const int N = 20010; 9 const int M = 60 ; 10 11 template < class T > 12 void read( T& x ){ 13 x = 0; 14 int f = 1 ; 15 char c = getchar() ; 16 while( c<'0'||c>'9' ) { 17 if (c == '-') f = -1; 18 c = getchar(); 19 } 20 while( c>='0'&&c<='9' ) { 21 x = x * 10 + c - '0'; 22 c = getchar(); 23 } 24 x = x * f ; 25 } 26 inline ll max( ll x,ll y ){ 27 return x > y ? x : y ; 28 } 29 typedef struct Edge { 30 int to , next ; 31 }Edge ; 32 Edge e[N<<1] ; 33 int n,Q,head[N],cnt; 34 35 inline void add_edge(int u,int v){ 36 e[ cnt ] = Edge{ v , head[u] }; 37 head[u] = cnt ++ ; 38 } 39 40 ll G[N],p[N][16][M+1],Ans[M+1]; //价值,树上线性基,答案线性基 41 int up[N][16],dep[N] ; //前缀第2^k个 和 深度 42 43 inline void Insert( ll x ){ 44 for(int i = M ; ~i ; i-- ){ 45 if( x >> i ){ 46 if( !Ans[i] ) { Ans[i] = x ; break ; } 47 else x ^= Ans[i] ; 48 } 49 } 50 } 51 inline void Insert( int u , int d , ll x ){ 52 for(int i = M ; ~i ; i-- ){ 53 if( x >> i ){ 54 if( !p[u][d][i] ) { p[u][d][i] = x ; break; } 55 else x ^= p[u][d][i] ; 56 } 57 } 58 } 59 60 void dfs(int u,int Fa){ 61 dep[u] = dep[Fa] + 1 ; 62 up[u][0] = Fa ; 63 64 Insert( u , 0 , G[u] ); 65 66 for(int i=1 ; i <= 15 ; i++ ){ 67 68 up[u][i] = up[up[u][i-1]][i-1]; // 爸爸的爸爸是爷爷 69 70 if( !up[u][i] ) break; // 因为根结点为虚点0 71 72 for( int j=M ; ~j ; j-- ){ 73 if( p[u][i-1][j] ) Insert( u , i , p[u][i-1][j] ); 74 if( p[up[u][i-1]][i-1][j] ) Insert( u , i ,p[up[u][i-1]][i-1][j] ); 75 } 76 } 77 for( register int i = head[u] ; ~i ; i=e[i].next ){ 78 if( e[i].to != Fa ) dfs( e[i].to , u ) ; 79 } 80 } 81 ll query ( int u , int v ){ 82 memset( Ans , 0 , sizeof Ans ); //对于多次询问,清空线性基 83 84 if( dep[u] < dep[v] ) swap(u, v); //默认u为更低点 85 86 for(int i=15;~i;i--){ //利用二进制的想法,爬到同一高度 87 if( dep[up[u][i]] >= dep[v] ){ //同时把对爬高的过程,对应结点的值插入线性基 88 for(int j=M;~j;j--) 89 if( p[u][i][j] ) Insert( p[u][i][j] ); 90 u = up[u][i] ; 91 } 92 } 93 94 if( u^v ){ //对于不同的位置来说,需要大家同时迈步走 95 for(int i=15;~i;i--){ 96 if( up[u][i] != up[v][i] ){ //双方都把对应的结点位置的值,插入答案线性基 97 for(int j=M;~j;j--){ 98 if( p[u][i][j] ) Insert( p[u][i][j] ); 99 if( p[v][i][j] ) Insert( p[v][i][j] ); 100 } 101 u = up[u][i] , v = up[v][i]; 102 } 103 } 104 Insert(G[u]), Insert(G[v]), Insert(G[up[u][0]]); 105 }else Insert(G[u]); 106 107 ll res = 0; 108 for(int j=M ; ~j ;j-- ){ 109 res = max ( res , res^Ans[j] ); 110 } 111 return res ; 112 } 113 114 int main(){ 115 memset( head,-1,sizeof head ); 116 read(n) , read(Q) ; 117 for( register int i=1 ; i<=n;i++ ) read(G[i]); 118 int u,v ; 119 for( register int i=1 ; i^n ;i++ ) { 120 read(u) , read(v) ; 121 add_edge(u, v), add_edge(v, u); 122 } 123 dfs(1, 0); 124 125 while( Q-- ){ 126 read(u), read(v) ; 127 printf("%lld ",query(u,v)); 128 } 129 return 0 ; 130 } 131 132 /* 133 * 134 4 2 135 11 5 7 9 136 1 2 137 1 3 138 1 4 139 2 3 140 1 4 141 142 14 143 11 144 */