wikioi 1245最小的N个和

2013-09-08 10:12

LRJ的算法竞赛入门经典训练指南里有类似的题,原题要难很多,p189页

读入A,B两组中的所有数后,建立N个有序表:

A1+B1<A2+B1<A3+B1<...<AN+B1

A1+B2<A2+B2<A3+B2<...<AN+B2

...

A1+BN<A2+BN<A3+BN<...<AN+AN

将每个有序表的第一个数字(记作s)连同A,B的下标0推入优先队列,这样我们每一次取出队列中的队首,显然这个元素的s是最小的,输出。与此同时,我们需要延续这个有序表。在取出的结构体中,令其标号a加1,b的标号不变,那么,s=B[b]+A[a]。

实际操作时,因为b的标号不变,就可以不保存下标b以及数组B,直接将读入数组B改为读入每一个元素(记为k),并将s=k+a[1],a=1推入队列,每次取出元素后,令其a=a+1,s=s+A[a]-A[a-1],如此减少空间占用,只需要一个队列和一个保存A的数组

//By BLADEVIL
type
    aa=record
    num                 :array[0..100010] of longint;
end;
    bb=record
    num,size            :longint;
 
end;
 
var
    x, y                :aa;
    n                   :longint;
    heap                :array[0..300010] of bb;
    t                   :longint;
 
 
procedure swap(var a,b:longint);
var
    z                   :longint;
begin
    z:=a; a:=b; b:=z;
end;
 
procedure qs(var xx:aa; low,high:longint);
var
    i, j, z,  c         :longint;
begin
    i:=low; j:=high; c:=xx.num[(i+j) div 2];
    while i<j do
    begin
        while c<xx.num[j] do dec(j);
        while c>xx.num[i] do inc(i);
        if i<=j then
        begin
            swap(xx.num[i],xx.num[j]);
            inc(i); dec(j);
        end;
    end;
    if i<high then qs(xx,i,high);
    if j>low then qs(xx,low,j);
end;
 
procedure init;
var
    i                   :longint;
begin
    read(n);
    for i:=1 to n do read(x.num[i]);
    for i:=1 to n do read(y.num[i]);
    qs(x,1,n);
    qs(y,1,n);
end;
 
procedure up(x:longint);
begin
    while (x>1) and (heap[x].num<heap[x div 2].num) do
    begin
        swap(heap[x].num,heap[x div 2].num);
        swap(heap[x].size,heap[x div 2].size);
        x:=x div 2;
    end;
end;
 
procedure down(x:longint);
var
    k                   :longint;
begin
    k:=x;
    while true do
    begin
        if (x<<1<=t) and (heap[k].num>heap[x<<1].num) then k:=x<<1;
        if (x<<1+1<=t) and (heap[k].num>heap[x<<1+1].num) then k:=x<<1+1;
        if k=x then exit;
        swap(heap[x].num,heap[k].num);
        swap(heap[x].size,heap[k].size);
        x:=k;
    end;
end;
 
procedure main;
var
    i                   :longint;
begin
    t:=0;
    for i:=1 to n do
    begin
        inc(t);
        heap[t].num:=x.num[i]+y.num[1];
        heap[t].size:=1;
        up(t);
    end;
    for i:=1 to n do
    begin
        write(heap[1].num,' ');
        inc(t);
        heap[t].num:=heap[1].num-y.num[heap[1].size]+y.num[heap[1].size+1];
        heap[t].size:=heap[1].size+1;
        up(t);
        heap[1].num:=heap[t].num;
        heap[1].size:=heap[t].size;
        dec(t);
        down(1);
 
    end;
    writeln;
end;
 
begin
    init;
    main;
end.

 

posted on 2013-11-20 14:18  BLADEVIL  阅读(363)  评论(0编辑  收藏  举报