XOR (莫隊)
Time Limit: 2000 ms Memory Limit: 256 MB
Description
給定一個含有n個整數的序列 a1, a2,..., an.
定義 f(x,x) = a[x], f(x,y) = a[x] xor a[x + 1] xor ... xor a[y] (y > x).
本題設有m組詢問,每組詢問含有兩個參數 (l, r) 。對於每組詢問,你需要回答有多少個二元組 (x, y) 滿足 l <= x <= y <= r 並且 f(x, y) = k.
Input
第一行有3個整數, n, m, k(1 <= n <= 100000, 1 <= m <= 100000, 0 <= k < 10^6).
第二行共有 n 個非負整數代表整個序列,每個整數均不超過 10^6.
接下來m行,每行兩個整數 (li, ri), li <= ri
Output
對於每組詢問,輸出一行表示有多少滿足上述條件的二元組。
Sample Input |
Sample Output |
5 2 1 |
2 4 |
Hint
對於10%的數據,$n, m \leq 500$
對於30%的數據,$n, m \leq 3000$
對於50%的數據,$n, m \leq 30000$
對於100%的數據,$n, m \leq 100000$
題解:
一看範圍就知道是標準$n\sqrt{n}$莫隊啊,是我今天感冒腦抽了想不出這麽簡單的處理嗎......
$[l,r]$異或起來的值剛好等於$k$,維護異或前綴和$a$後,等價於判斷$a_{l-1}\hat{} a_{r}$是否等於$k$。
那麽用莫隊在這個異或前綴和數組上爬。
維護莫隊中統計每種值出現次數的數組$cnt$,$cnt_i$表示值為$i$的有多少。
這樣一來,加入一位$x$對莫隊的影響就是$ans+=cnt_{a[x]\hat{} k}$,刪去一位對莫隊的影響就是$ans-=cnt_{a[x]\hat{} k}$
當然還要維護$cnt$,加入時先統計影響,再將$cnt_{a[x]}++$;刪除時先從$cnt$裏抹掉:$cnt_{a[x]}--$,再統計影響。
Tips:
1.原本$[l,r]$的詢問,轉換後最大要考慮到$[l-1,r]$,所以把詢問的左端點都-1.
2.異或後值可能大於1000000,需多開一倍。
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int N=100010; 7 int n,m,k,di,a[N],cnt[2000010]; 8 ll now,out[N]; 9 struct Query{ 10 int l,r,id; 11 friend bool operator < (Query x,Query y){ 12 x.l++; y.l++; 13 if(x.l/di!=y.l/di) return x.l/di<y.l/di; 14 return x.r<y.r; 15 } 16 }q[N]; 17 void add(int x){ 18 now+=cnt[a[x]^k]; 19 cnt[a[x]]++; 20 } 21 void dec(int x){ 22 cnt[a[x]]--; 23 now-=cnt[a[x]^k]; 24 } 25 int main(){ 26 scanf("%d%d%d",&n,&m,&k); 27 di=(int)sqrt(n); 28 for(int i=1,x;i<=n;i++){ 29 scanf("%d",&x); 30 a[i]=a[i-1]^x; 31 } 32 for(int i=1;i<=m;i++){ 33 scanf("%d%d",&q[i].l,&q[i].r); 34 q[i].l--; q[i].id=i; 35 } 36 sort(q+1,q+1+m); 37 int l=1,r=1; 38 cnt[a[1]]=1; 39 for(int i=1;i<=m;i++){ 40 while(r<q[i].r) add(++r); 41 while(r>q[i].r) dec(r--); 42 while(l<q[i].l) dec(l++); 43 while(l>q[i].l) add(--l); 44 out[q[i].id]=now; 45 } 46 for(int i=1;i<=m;i++) printf("%lld\n",out[i]); 47 return 0; 48 }奇妙代碼
XOR (莫隊)