有序表的最小和
【問題描述】
給出長度爲n得有序表A和B,在A和B中各取一個元素,可以得到n^2個和,求這些和中最小的n個
【輸入格式】
第一行包含一個整數n(n<=400000)
第二行與第三行分別n個整數,從小到大排列
【輸入樣例】
3
1 2 5
2 4 7
【輸出樣例】
3
4
5
【算法分析】
A[1]<=A[2]<=A[3]<=a[4]...
B[1]<=B[2]<=B[3]<=B[3]...
設C[a,b]=A[a]+B[b]
可知對於每一個a來說
C[a,1]<=C[a,2]<=C[a,3]...
此時C[a]構成一個數列
每一次生成的最小值必定是C[a](1<=a<=n)每個數列的頭中最小的
例如
1 2 5
2 4 7
C[a,b]
a/b 1 2 3
1 3 5 8
2 4 6 9
3 7 9 12
第一個最小的數必定在3,4,7三數之間 爲3,3去掉,此時c[1]表頭爲5
第二個最小的數必定在5,4,7三數之間 爲4, 4去掉,此時c[2表頭爲6
第三個最小的數必定在5,6,9三數之間 爲5, 5去掉,此時c[1]表頭爲8
【算法實現】
由此我們可以維護一個小根堆
開始時這個堆有n個元素,它們爲每個表的頭元素c[a,1](1<=a<=n)
每次取出小根堆的根元素並將該元素所在表的表頭更新:其實並沒有必要建表,只需修改該根元素的值爲該表下一個值即可
維護堆,重複n次
【程序】
<span style="font-size:14px;">//2016-4-7
//Gods save princess!
//By Shui'bing ICEE
const
maxn=500000;//!!!!!
type
node=record
b,data:longint;
end;
var
heap:array[0..maxn] of node;
a,b:array[0..maxn] of longint;
i,n,l:longint;
procedure put(x,b:longint);
var
son,temp:longint;
begin
inc(l);
heap[l].b:=b;
heap[l].data:=x;
son:=l;
while (son<>1) and (heap[son div 2].data>heap[son].data) do
begin
temp:=heap[son div 2].data;
heap[son div 2].data:=heap[son].data;
heap[son].data:=temp;
temp:=heap[son div 2].b;
heap[son div 2].b:=heap[son].b;
heap[son].b:=temp;
end;
end;
function get:longint;
var
fa,son,temp:longint;
stop:boolean;
begin
get:=heap[1].data;
heap[1].data:=heap[1].data-b[heap[1].b]+b[heap[1].b+1];
inc(heap[1].b);
fa:=1;
stop:=false;
while (fa*2<=l) and (not stop) do
begin
if (fa*2+1>l) or (heap[fa*2].data<heap[fa*2+1].data)
then son:=fa*2
else son:=fa*2+1;
if heap[fa].data>heap[son].data
then begin
temp:=heap[fa].data;
heap[fa].data:=heap[son].data;
heap[son].data:=temp;
temp:=heap[fa].b;
heap[fa].b:=heap[son].b;
heap[son].b:=temp;
end
else stop:=true;
end;
end;
begin
read(n);
for i:=1 to n do
read(a[i]);
for i:=1 to n do
read(b[i]);
l:=0;
for i:=1 to n do
begin
put(a[i]+b[1],1);
end;
for i:=1 to n do
writeln(get);
end.</span>