bzoj 3689: 异或之

3689: 异或之

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 458  Solved: 212
[Submit][Status][Discuss]

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数可以去出某个数与一坨数第k异或值,我们把每个数二进制拆分,用trie树储存起来。
  维护一个堆,刚开始把每个数与其他数的第二小异或值放进去(第一小是与它本身),然后每次从堆中取数,再把取出来的数的下一个最小值放进去,因为每个异或值会被重复取两次,所以选择奇数次输出。 
*/
#include<cstdio>
#include<iostream>
#include<queue>
#define N 100010
using namespace std;
int a[N],ch[N*30][3],size[N*30],n,k,cnt;
struct node{
    int v,a,k;
};
bool operator < (node s1,node s2){
    return s1.v>s2.v;//小根堆 
}
priority_queue<node> q;
void insert(int x){
    int now=0;
    for(int i=30;i>=0;i--){//从高位到低位 
        int t=x&(1<<i);t>>=i;
        if(!ch[now][t])ch[now][t]=++cnt;
        now=ch[now][t];size[now]++;
    }
}
int query(int x,int k){//二进制分解结果越相像,异或值越小 
    int now=0,tmp=0;
    for(int i=30;i>=0;i--){
        int t=x&(1<<i);t>>=i;
        if(size[ch[now][t]]>=k)now=ch[now][t];
        else k-=size[ch[now][t]],now=ch[now][t^1],tmp+=(1<<i);
    }
    return tmp;
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        insert(a[i]);//将所有数字存到字典树中 
    }
    for(int i=1;i<=n;i++){//枚举每个数字 
        node x;
        x.v=query(a[i],2);x.k=2;x.a=a[i];//找到第2小的异或值 
        q.push(x);
    }
    for(int i=1;i<k*2;i++){
        node x=q.top();q.pop();
        if(i&1)printf("%d ",x.v);
        x.k++;x.v=query(x.a,x.k);
        q.push(x);
    }
    return 0;
}

 

posted @ 2017-11-07 17:04  Echo宝贝儿  阅读(242)  评论(0编辑  收藏  举报