题目描述
有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2N2个和,求这N^2N2个和中最小的N个。
输入格式
【数据规模】
对于50%的数据中,满足1<=N<=1000;
对于100%的数据中,满足1<=N<=100000。
输出格式
输出仅一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。
输入输出样例
输入 #1
3 2 6 6 1 4 8输出 #1
3 6 7
这道题一开始我是用小顶堆做的,先无脑了一波,把数据存入小顶堆后然后输出前n个数据。
只有76分,内存超限。
后来呢,改用了大顶堆。
思路是:用大顶堆来维护n个数据,最开始已经输入了第一行数据,然后先接收第二行的第一个数据b【1】,将b【1】+a【i】这n个数据作为初始数据放在大顶堆中。
【注意:两行输入数据是从小到大的顺序的】
然后从第二行的第二个数据开始接受,每次将接受的值循环与a【i】相加,要做一个判断,如果当前数据已经大于了大顶堆最大值,就无须继续该轮加a【i】的循环,这里剪枝了很多无效操作。如果小于当前大顶堆第一个值,那就把大顶堆top值弹出去,把该值入堆。
最后将堆里的数据取出到数组中,然后再倒序输出。速度非常快。
AC代码:
#include<bits/stdc++.h>
using namespace std;
priority_queue<int> p;//大顶堆
int n,a[100000],b[100000];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
cin>>b[1];
for(int i=1;i<=n;i++)p.push(a[i]+b[1]);
for(int i=2;i<=n;i++){
cin>>b[i];
for(int j=1;j<=n;j++){
if(a[j]+b[i]>p.top()){
break;
}else{
p.pop();
p.push(a[j]+b[i]);
}
}
}
for(int i=1;i<=n;i++){
a[i]=p.top();
p.pop();
}
for(int i=n;i>=1;i--)cout<<a[i]<<" ";
return 0;
}