码迷,mamicode.com
首页 > 其他好文 > 详细

[模板]线性基

时间:2018-12-04 20:37:27      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:div   ==   结束   sign   const   getch   ||   nbsp   turn   

用途

处理关于子集的异或和的问题,比如子集异或和的最大值,或者能不能异或出某个数

原理

从一堆数中处理出一组线性无关(?)的数,使得这些数能异或出的数和原来能异或出的数相同

线性基中,以每个位置为最高位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了

 

[模板]线性基

标签:div   ==   结束   sign   const   getch   ||   nbsp   turn   

原文地址:https://www.cnblogs.com/Ressed/p/10066528.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!