BZOJ3689 异或之
题面
题目描述
给定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++中的“^”。
输入
第一行2个正整数 n,k,如题所述。
以下n行,每行一个非负整数表示A[i]。
输出
共一行k个数,表示前k小的数。
样例输入
4 5
1
1
3
4
样例输出
0 2 2 5 5
【样例解释】
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树上可以找到一个数的xor第k大(小).
我们把每个数的异或第\(2\)小先装进堆里面(异或第\(1\)小是自己异或自己, 不在题目考虑范围内), 每次取出堆头, 假设堆头是第\(p\)小, 则插入第\(p + 1\)小即可.
注意应该取\(2k\)次, 因为每两次得到的结果是相同的.
#include <cstdio>
#include <cctype>
#include <queue>
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1;
char c;
while(! isdigit(c = getchar()))
if(c == '-')
sgn *= -1;
while(isdigit(c))
a = a * 10 + c -'0', c = getchar();
return a * sgn;
}
inline void print(int a)
{
if(! a)
return;
print(a / 10);
putchar(a % 10 + '0');
}
inline void println(int a)
{
if(a < 0)
putchar('-'), a *= -1;
if(a == 0)
putchar('0');
print(a);
putchar(' ');
}
}
const int N = 100000;
struct trieTree
{
struct node
{
node *suc[2];
int cnt;
inline node()
{
suc[0] = suc[1] = NULL;
cnt = 0;
}
};
node *rt;
inline trieTree()
{
rt = new node;
}
inline void insert(int w)
{
node *u = rt;
for(int i = 30; ~ i; -- i)
{
int k = w >> i & 1;
if(u->suc[k] == NULL)
u->suc[k] = new node;
++ (u = u->suc[k])->cnt;
}
}
inline int query(int w, int k)
{
node *u = rt;
int res = 0;
for(int i = 30; ~ i; -- i)
{
int tmp = w >> i & 1;
if(u->suc[tmp] != NULL && u->suc[tmp]->cnt >= k)
u = u->suc[tmp];
else
k -= u->suc[tmp] == NULL ? 0 : u->suc[tmp]->cnt, u = u->suc[tmp ^ 1], res += 1 << i;
}
return res;
}
}trie;
struct record
{
int id, k, w;
inline record(int _id, int _k ,int _w)
{
id = _id, k = _k, w = _w;
}
inline int friend operator <(record a, record b)
{
return a.w > b.w;
}
};
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ3689.in", "r", stdin);
#endif
using namespace Zeonfai;
int n = getInt(), k = getInt();
static int a[N];
for(int i = 0; i < n; ++ i)
trie.insert(a[i] = getInt());
static std::priority_queue<record> hp;
for(int i = 0; i < n; ++ i)
hp.push(record(i, 2, trie.query(a[i], 2)));
for(int i = 0; i < k << 1; ++ i)
{
record res = hp.top();
hp.pop();
if(i & 1)
println(res.w);
if(res.k < n)
hp.push(record(res.id, res.k + 1, trie.query(a[res.id], res.k + 1)));
}
}