1. 程式人生 > >[BZOJ3689] 異或之

[BZOJ3689] 異或之

Description

給定n個非負整數A[1], A[2], ……, A[n]。
對於每對(i, j)滿足1 <= i < j <= n,得到一個新的數A[i] xor A[j],這樣共有n*(n-1)/2個新的數。求這些數(不包含A[i])中前k小的數。
注:xor對應於pascal中的“xor”,C++中的“^”。

Input

第一行2個正整數 n,k,如題所述。
以下n行,每行一個非負整數表示A[i]。

Output

 共一行k個數,表示前k小的數。

Sample Input

4 5
1
1
3
4

Sample Output

0 2 2 5 5

HINT

【樣例解釋】

1 xor 1 = 0 (A[1] xor A[2])

1 xor 3 = 2 (A[1] xor A[3])

1 xor 4 = 5 (A[1] xor A[4])

1 xor 3 = 2 (A[2] xor A[3])

1 xor 4 = 5 (A[2] xor A[4])

3 xor 4 = 7 (A[3] xor A[4])

前5小的數:0 2 2 5 5

【資料範圍】

 對於100%的資料,2 <= n <= 100000; 1 <= k <= min{250000, n*(n-1)/2};

        0 <= A[i] < 2^31

 

 


 

 

這題和Noi2010超級鋼琴特別像。

首先把每個數都插進01Trie裡,然後把每個對於每個數的異或值的第二小放入小根堆中(因為第一小一定是他自己)。

查詢異或值的第k小和線上段樹上二分查詢第k小類似,維護0/1兒子的size,然後像線段樹一樣分類討論一下。

我們從堆中取出當前最小的值,然後把這個位置的下一個最小值插進堆裡,一直這樣維護就行了。

因為一個最小值會被它的兩個元素同時列舉到,所以我們只要在奇數位置上輸出就行了。

 


 

 

 

#include <iostream>
#include 
<cstdio> #include <algorithm> #include <cstring> #include <vector> #include <queue> #include <map> using namespace std; #define reg register inline int read() { int res = 0;char ch=getchar();bool fu=0; while(!isdigit(ch))fu|=(ch=='-'),ch=getchar(); while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=getchar(); return fu?-res:res; } #define mkp make_pair #define pii pair<int, int> #define N 100005 int n, K; int a[N]; int nxt[N*31][2], siz[N*31], tot; inline void ins(int v) { int now = 0; for (reg int i = 31 ; i >= 0 ; i --) { bool d = v & (1ll << i); if (!nxt[now][d]) nxt[now][d] = ++tot; now = nxt[now][d]; siz[now]++; } } int timc[N]; inline int Findk(int v, int k) { int now = 0, res = 0; for (reg int i = 31 ; i >= 0 ; i --) { bool d = v & (1ll << i); if (siz[nxt[now][d]] >= k) now = nxt[now][d]; else k -= siz[nxt[now][d]], now = nxt[now][d^1], res |= (1ll << i); } return res; } int main() { n = read(), K = read(); for (reg int i = 1 ; i <= n ; i ++) ins(a[i] = read()); priority_queue <pii, vector<pii>, greater<pii> > q; for (reg int i = 1 ; i <= n ; i ++) { q.push(mkp(Findk(a[i], 2), i)); timc[i] = 3; // printf("%d %d\n",i, Findk(a[i], 2)); } for (reg int i = 1 ; i <= K<<1 ; i ++) { int tp = q.top().first, id = q.top().second;q.pop(); if (i & 1) printf("%d ", tp); if (timc[id] == n) continue; q.push(mkp(Findk(a[id], timc[id]), id)); timc[id]++; } return 0; }