解题思路
观察题目,
A
,
B
A,B
A,B数组都已近按从小到大的顺序排序,我们可以轻松得出一个结论:
A
[
i
]
+
B
[
j
]
<
=
A
[
i
]
+
B
[
j
+
1
]
A[i]+B[j]<=A[i]+B[j+1]
A[i]+B[j]<=A[i]+B[j+1],然后根据这个结论我们可以把那些和看成形成了n个有序队列:
A
[
1
]
+
b
[
1
]
=
A
[
1
]
+
B
[
2
]
…
…
<
=
A
[
1
]
+
B
[
N
]
A[1]+b[1]=A[1]+B[2]……<=A[1]+B[N]
A[1]+b[1]=A[1]+B[2]……<=A[1]+B[N]
A
[
2
]
+
b
[
1
]
=
A
[
2
]
+
B
[
2
]
…
…
<
=
A
[
2
]
+
B
[
N
]
A[2]+b[1]=A[2]+B[2]……<=A[2]+B[N]
A[2]+b[1]=A[2]+B[2]……<=A[2]+B[N]
……
A
[
N
]
+
b
[
1
]
=
A
[
N
]
+
B
[
2
]
…
…
<
=
A
[
N
]
+
B
[
N
]
A[N]+b[1]=A[N]+B[2]……<=A[N]+B[N]
A[N]+b[1]=A[N]+B[2]……<=A[N]+B[N]
显然,求最小可以用小根堆优化,首先将这N个队列中的第一个元素放入一个堆中:然后每次取出堆中的最小值。若这个最小值来自于第k个队列,那么,就将第k个队列的下一个元素放入堆中。
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int n,len,a[1000010],b[1000010];
struct c{
int x,y,w;
}tree[1000010];
void put(int x,int y){
len++;
tree[len].x=x,tree[len].y=y,tree[len].w=a[x]+b[y];
int son=len;
while(son>1)
{
int fa=son/2;
if(tree[fa].w<=tree[son].w)
break;
swap(tree[fa],tree[son]);
son=fa;
}
}
int get(){
int kl=tree[1].w,x=tree[1].x,y=tree[1].y,fa=1;
swap(tree[1],tree[len--]);
while(fa*2<=len)
{
int son=fa*2;
if(son+1<=len&&tree[son+1].w<tree[son].w)
son++;
if(tree[fa].w<=tree[son].w)
break;
swap(tree[fa],tree[son]);
fa=son;
}
put(x,y+1);
return kl;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
put(i,1);
for(int i=1;i<=n;i++)
printf("%d ",get());
}