题意:给定一个非负整数序列,两两异或,求前k小的异或值
显然,如果一个数想和其他数异或尽量小,肯定是化为二进制后,从最高位起能选这一位相同的就选能和这一位相同的,实在没有再选和这一位不同的(当这一位不同,异或后的答案一定有2^i),这一位确定后再看下一位
那么我们就对所有数的二进制建trie树,同时统计size(有几个数的这一位和当前数是相同的)
然后所有数与其他数异或值的第二小(第一小是自己异或自己)丢到一个小根堆里,当取出一个数异或值的第k‘小,就把第k’+1小丢进堆里
这样,一个异或值会被取出两次,所以我们总共需要取出2*k次,取到奇数次时输出
小tip:堆里直接是结构体时,Pascal会有大常数(会变慢),所以我们在堆里维护编号,在外面维护每个编号的相关信息即可
uses math;
type
rec=record
num,id,w:longint;
end;
var
n,k,tot,sizee :longint;
maxn :longint;
i :longint;
b :array[0..4000010] of rec;
heap,a :array[0..4000010] of longint;
t :array[0..4000010,0..1] of longint;
size :array[0..4000010] of longint;
procedure swap(var a,b:longint);
var
c:longint;
begin
c:=a; a:=b; b:=c;
end;
procedure heap_up(i:longint);
begin
if i=1 then exit;
while i>1 do
begin
if b[heap[i]].w<b[heap[i>>1]].w then
begin
swap(heap[i],heap[i>>1]);
i:=i>>1;
end else exit;
end;
end;
procedure heap_down(i:longint);
var
t:longint;
begin
while (i<<1)<=sizee do
begin
if b[heap[i]].w<b[heap[i<<1]].w then t:=i else t:=i<<1;
if (i<<1)+1<=sizee then
if b[heap[t]].w>b[heap[(i<<1)+1]].w then t:=(i<<1)+1;
if i<>t then
begin
swap(heap[i],heap[t]);
i:=t;
end else exit;
end;
end;
procedure insert_heap(i:longint);
begin
inc(sizee);
heap[sizee]:=i;
heap_up(sizee);
end;
procedure insert(x:longint);
var
rt,y,i:longint;
begin
rt:=0;
for i:=maxn downto 0 do
begin
if (x and (1<<i))<>0 then y:=1 else y:=0;
if t[rt,y]=0 then
begin
inc(tot);
t[rt,y]:=tot;
end;
rt:=t[rt,y]; inc(size[rt]);
end;
end;
function find(id,k:longint):longint;
var
ans,rt,i,x:longint;
begin
ans:=0; rt:=0;
for i:=maxn downto 0 do
begin
if (a[id] and (1<<i))<>0 then x:=1 else x:=0;
if size[t[rt,x]]>=k then rt:=t[rt,x] else
begin
inc(ans,1<<i); dec(k,size[t[rt,x]]); rt:=t[rt,x xor 1];
end;
end;
exit(ans);
end;
function work(x:longint):longint;
var
ans:longint;
begin
ans:=0;
while x>0 do
begin
inc(ans);
x:=x>>1;
end;
exit(ans);
end;
begin
read(n,k);
for i:=1 to n do read(a[i]);
for i:=1 to n do maxn:=max(maxn,work(a[i]));
for i:=1 to n do insert(a[i]);
for i:=1 to n do
begin
b[i].id:=i; b[i].num:=2; b[i].w:=find(i,2);
insert_heap(i);
end;
for i:=1 to (k<<1)do
begin
if i and 1=1 then write(b[heap[1]].w,' ');
if b[heap[1]].num=n then
begin
dec(sizee); continue;
end;
b[heap[1]].w:=find(b[heap[1]].id,b[heap[1]].num+1);
inc(b[heap[1]].num);
heap_down(1);
end;
writeln;
end.
——by Eirlys