用途
处理关于子集的异或和的问题,比如子集异或和的最大值,或者能不能异或出某个数
原理
从一堆数中处理出一组线性无关(?)的数,使得这些数能异或出的数和原来能异或出的数相同
线性基中,以每个位置为最高位1的数(最多)只有一个,这样就保证了线性无关
做法
依次处理每个数,对于x,从大到小扫描它的每一位,当扫到第i位为1时:
若线性基中没有最高位为i的数,则把x插到线性基中,结束扫描
若有,则把x异或上那个数,继续做
这样做,如果一个数最终没有被插入线性基中,证明它已经能被线性基中的数表示
而插到线性基中的数,也一定是几个原数的异或和
最后我如果想找能异或出的最大的数,那就从高到低扫线性基中的每个数,如果异或上能使答案变大,就异或上,毕竟机不可失时不再来
例题
luogu3812
1 #include<bits/stdc++.h> 2 #define CLR(a,x) memset(a,x,sizeof(a)) 3 #define MP make_pair 4 using namespace std; 5 typedef long long ll; 6 typedef unsigned long long ull; 7 typedef pair<int,int> pa; 8 const int maxn=55; 9 10 inline ll rd(){ 11 ll x=0;char c=getchar();int neg=1; 12 while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=-1;c=getchar();} 13 while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar(); 14 return x*neg; 15 } 16 17 int N; 18 ll a[maxn],x[maxn]; 19 20 int main(){ 21 //freopen("","r",stdin); 22 int i,j,k; 23 N=rd(); 24 for(i=1;i<=N;i++) a[i]=rd(); 25 for(i=1;i<=N;i++){ 26 for(j=50;j>=0;j--){ 27 if(a[i]&(1ll<<j)){ 28 if(!x[j]){ 29 x[j]=a[i];break; 30 }else a[i]^=x[j]; 31 } 32 } 33 } 34 ll ans=0; 35 for(i=50;i>=0;i--){ 36 if((ans^x[i])>ans) ans^=x[i]; 37 } 38 printf("%lld\n",ans); 39 return 0; 40 }
如果您像我一样容易忘记写break的话,可以考虑不写else,反正如果我这次插进去了,再异或上我自己就变成了0,就相当于break了
原文地址:https://www.cnblogs.com/Ressed/p/10066528.html
时间: 2024-10-05 09:19:27