有序表的最小和

有序表的最小和

【问题描述】

给出长度为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

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>


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值