1. 程式人生 > >[模板]線性基

[模板]線性基

int getchar() 它的 turn 繼續 def lin 相同 掃描

用途

處理關於子集的異或和的問題,比如子集異或和的最大值,或者能不能異或出某個數

原理

從一堆數中處理出一組線性無關(?)的數,使得這些數能異或出的數和原來能異或出的數相同

線性基中,以每個位置為最高位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了

[模板]線性基