1. 程式人生 > >51nod 1577 異或湊數(線性基)

51nod 1577 異或湊數(線性基)

超過 txt opera ios inf ring bool insert 分析

技術分享

分析:如果能知道區間線性基,問題就解決了,所以一開始有個naive的想法,搞個線性基線段樹,然而復雜度(32*nlogn),果斷T。。。

正解是預處理後綴線性基,並且每個基中的每一個分量位置盡量靠前,然後把k丟到左端點對應的線性基裏跑,如果k最後不為0或者需要異或的位置超過了r,答案就是NO。

這樣的後綴線性基可以從後面開始處理,插入x時,如果某一位已經有數且在數組中的位置在x之後,把x放入線性基替換掉這個數,然後用這個數接著跑。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4
#define SWAP(x, y)x ^= y, y ^=x, x ^= y; 5 using namespace std; 6 const int maxn = 5e5 + 5, inf = 1e9; 7 int n; 8 struct LinearBase{ 9 int a[32], n, loca[32]; 10 LinearBase(){ 11 memset(a, 0, sizeof(a)); 12 memset(loca, 0, sizeof(loca)); 13 n = 0; 14 } 15 void
insert(int x, int k){ 16 int cur_loca = k; 17 int d = 31; 18 while(x && d >= 0){ 19 if(x & (1 << d)){ 20 if(a[d]){ 21 if(cur_loca < loca[d]){ 22 SWAP(loca[d], cur_loca); 23 SWAP(a[d], x);
24 } 25 x ^= a[d]; 26 }else{ 27 loca[d] = cur_loca; 28 a[d] = x; 29 n++; 30 break; 31 } 32 } 33 d--; 34 } 35 } 36 LinearBase operator = (LinearBase x){ 37 x.n = n; 38 for(int i = 0; i < 32; i++)a[i] = x.a[i], loca[i] = x.loca[i]; 39 } 40 int check(int k){ 41 int d = 31, r_min = 0; 42 while(k && d>=0){ 43 if(k & (1 << d)){ 44 if(!a[d])return inf; 45 r_min = max(r_min, loca[d]); 46 k ^= a[d]; 47 } 48 d--; 49 } 50 if(k)return inf; 51 return r_min; 52 } 53 }lb[maxn]; 54 int read(){ 55 int ans = 0; 56 char last = , ch = getchar(); 57 while(ch >= 0 && ch <= 9)ans = ans * 10 + ch - 0, ch = getchar(); 58 return ans; 59 } 60 bool check(int l, int r, int k){ 61 LinearBase &b = lb[l]; 62 if(b.check(k) <= r)return true; 63 return false; 64 } 65 int a[maxn]; 66 int main(){ 67 // freopen("e:\\in.txt","r",stdin); 68 n = read(); 69 for(int i = 1; i <= n; i++)a[i] = read(); 70 lb[n].insert(a[n], n); 71 for(int i = n - 1; i >= 0; i--){ 72 lb[i] = lb[i + 1]; 73 lb[i].insert(a[i], i); 74 } 75 int m,l,r,k; 76 m = read(); 77 for(int i = 0; i < m; i++){ 78 l = read();r = read();k = read(); 79 if(check(l, r, k))puts("YES"); 80 else puts("NO"); 81 } 82 return 0; 83 }

51nod 1577 異或湊數(線性基)