序列合并
问题描述
有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2个和,求这N^2个和中最小的N个(n<=100000)。
分析
a[i]与b[j]相加后,下面相加的一定是a[i+1]+b[j]或a[i]+b[j+1],一开始我们把b[1]与a中所有元素相加放入一个小根堆里,输出min,然后把堆顶与b[2]相加,维护堆后输出……,为避免重复相加,需要开一个数组记录堆里第i个元素是与b中第几个元素相加的结果,在下次相加是直接加b中下一个。
时间复杂度
O(n logn)
代码
const
maxn=100000;
type
arr=array[0..maxn] of longint;
var
a,b,c,p:arr;
i,j,n,m:longint;
procedure down(i:longint);
var
done:boolean;
begin
done:=false;
repeat
i:=2*i;
if (i+1<=n) and (p[i]>p[i+1]) then inc(i);
if p[i div 2]>p[i] then
begin
c[0]:=c[i];
c[i]:=c[i div 2];
c[i div 2]:=c[0];
p[0]:=p[i];
p[i]:=p[i div 2];
p[i div 2]:=p[0];
end
else done:=true;
until (2*i>n) or done;
end;
begin
readln(n);
for i:=1 to n do
read(a[i]);
for i:=1 to n do
read(b[i]);
for i:=1 to n do
begin
c[i]:=1;
p[i]:=a[i]+b[1];
end;
for i:=n div 2 downto 1 do
down(i);
for i:=1 to n do
begin
write(p[1],' ');
p[1]:=p[1]-b[c[1]]+b[c[1]+1];
inc(c[1]);
down(1);
end;
end.