题目描述
有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2个和,求这N^2个和中最小的N个。
输入输出格式
输入格式:
第一行一个正整数N;
第二行N个整数Ai,满足Ai<=Ai+1且Ai<=10^9;
第三行N个整数Bi, 满足Bi<=Bi+1且Bi<=10^9.
【数据规模】
对于50%的数据中,满足1<=N<=1000;
对于100%的数据中,满足1<=N<=100000。
输出格式:
输出仅一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。
输入样例#1:
3 2 6 6 1 4 8
输出样例#1:
3 6 7
//这道题和最小函数值思路差不多,不用全部枚举,否则会导致数组开爆或者很慢。将a,b排序后把b[1]带入枚举a,建堆;值得一提的是要建大根堆,原因是要与堆顶元素比对决定是否有必要入堆,这是一个小剪枝。还有要注意的是枚举其余b时每个元素入堆前都要删除堆顶,置换堆顶。最后不要忘了逆序输出,原因是大根堆排序从大到小qwq
//上代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n;int hp[maxn];int a[maxn];int b[maxn];
int i,j;int siz;int ans[maxn];
void pus(int x);
int del();
int main()
{
cin>>n;
siz=0;
for (i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=1;i<=n;++i) scanf("%d",&b[i]);
sort(a+1,a+n+1);sort(b+1,b+n+1);
for (i=1;i<=n;++i)
pus(a[i]+b[1]);//a,b都是序列为对比先用b[1]建堆
for (i=1;i<=n;++i)
for (j=2;j<=n;++j)//1已经尝试过
{
if (a[i]+b[j]>=hp[1]) break;//比堆顶大的直接GG
del();//删堆顶
// cout<<"i="<<i<<" "<<"j="<<j<<" "<<endl;for(int z=1;z<=10;z++) cout<<hp[z]<<" ";cout<<endl;
pus(a[i]+b[j]);//入堆 //置换堆顶
// for(int z=1;z<=10;z++) cout<<hp[z]<<" ";
}
for(i=1;i<=n;++i) ans[i]=del();//从大到小排序
for(i=n;i>=1;--i) printf("%d ",ans[i]);//逆序输出
printf("\n");
return 0;
}
void pus(int x){
siz++;
hp[siz]=x;
int now=siz;
while(now>1){
if(hp[now]>hp[now/2]){
swap(hp[now],hp[now/2]);
now/=2;
}//if
else break;
}//while
}//void
int del(){
int res=hp[1];
hp[1]=hp[siz];siz--;
int now=1;
while(2*now<=siz){
int tp=2*now;
if(tp<siz && hp[tp]<hp[tp+1]) tp=tp+1;
if(hp[now]<hp[tp]){
swap(hp[now],hp[tp]);
now=tp;
}//if
else break;
} //while
return res;
}