题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=3689
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
Trie树+堆
可以对每一个数的二进制建一棵Trie树,这样就可以通过每一个节点的
size
快速查询出一个数与其它数异或值的第
k
小
维护一个小根堆,将每个数异或的第二小扔入堆中(第一小是它自己),表示是与这个数异或出的第二小的数,在取出堆顶的同时,则取出的数数可以看做与
然而这样会有重复的答案,
a
^
代码如下:
#include<algorithm>
#include<cstdio>
#include<queue>
#define N 4000010
using namespace std;
const int maxx=32;
int ch[N][2],size[N];
int a[N];
int top,n,m,k,ans,x;
struct Elem{
int w,id,num;
bool operator > (const Elem b) const{
return w>b.w;
}
Elem(){}
Elem(int _,int __,int ___):w(_),id(__),num(___){}
};
priority_queue<Elem,vector<Elem>,greater<Elem> > q;
void add(int t){
x=0;
for(int i=maxx-1;i>=0;i--){
int p=t>>i&1;
if(!ch[x][p]) ch[x][p]=++top;
size[x=ch[x][p]]++;
}
}
int query(int id,int k){
ans=x=0;
for(int i=maxx-1;i>=0;i--){
int p=a[id]>>i&1;
if(size[ch[x][p]]>=k) x=ch[x][p];
else ans+=(1<<i),k-=size[ch[x][p]],x=ch[x][p^1];
}
return ans;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=n;i++) add(a[i]);
for(int i=1;i<=n;i++) q.push(Elem(query(i,2),i,2));
for(int i=1;i<=2*k;i++){
Elem t=q.top();q.pop();
if(i&1) printf("%d ",t.w);
if(t.num==n) continue;
t.w=query(t.id,++t.num);
q.push(t);
}
return 0;
}