BZOJ3689: 异或之

本文探讨了使用0/1 Trie数据结构解决一对非负整数数组中所有可能的异或组合,寻找前k小的异或结果的问题。通过对子树大小的记录,采用二分查找策略确定第k大的数值,并通过堆数据结构进行有效管理,确保了算法的高效运行。

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++中的“^”。

 


【数据范围】

 对于100%的数据,2 <= n <= 100000; 1 <= k <= min{250000, n*(n-1)/2};

        0 <= A[i] < 2^31

 

 

Solution

两两异或,经典的0/1trie问题。

通过记录子树的size可以二分找到第k大。

然后比较暴力地找前k大。

把trie建好。

首先把所有的数与其他数异或值的第二大放进堆里。(第一大一定是自己,不符合题意)

这样,最小的肯定包含了。把最小的取出来。然后把产生这个最小值的数的第三大异或值再放进去。。。

第二小的异或值肯定也包含了。

注意的是,每个异或值取过最小的时候,必然另一半也会把这个最小值放进去。

所以每个异或值会出现两遍。

只要取2*k次堆顶,奇数次输出答案即可。

转载于:https://www.cnblogs.com/Miracevin/p/9854271.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值