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.