1245 最小的N个和
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。
输入描述 Input Description
第一行输入一个正整数N;第二行N个整数Ai 且Ai≤10^9;第三行N个整数Bi,
且Bi≤10^9
输出描述 Output Description
输出仅一行,包含 n 个整数,从小到大输出这 N个最小的和,相邻数字之间用
空格隔开。
样例输入 Sample Input
5
1 3 2 4 5
6 3 4 1 7
样例输出 Sample Output
2 3 4 4 5
数据范围及提示 Data Size & Hint
【数据规模】 对于 100%的数据,满足 1≤N≤100000。
写在前面:我以后再也不碰没学过的数据结构题目了(论自学的必要性,不要觉得自己什么都会,不看就去写!(/▽╲))
——————————————————————————————————————————————
解题思路:刚开始我拿到这道题发现要用堆写,然后我就崩溃了,因为我不会!我不会!我不会!后来自己看了一点基本操作,又做了几道非常基础的练习才拿过来再写,后来发现不是我想象的那么容易,刚开始我是想到了取a[i]b[j]必定要取a[i-1]b[j]和a[i][j-1],但是我发现数据范围太大,然后就不知道怎么去存储和调用,然后只能去问问Yveh大爷,后来他给我发了个解题思路,然后写出来了……
先对ab排序,然后
就像这样,我们发现让b(或a)的第一个元素去和所有的a(b)中的元素相加并入堆(边入边维护,这里用小根堆),然后进行n次循环,吧堆顶元素弹出,然后堆顶元素更新为原堆顶元素同一行右边的数字,再次维护即可,这样做是一定可以找到前n个最小和的
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,len,t,x,a[100001],b[100001],answer[100001];
struct os
{
int num,sum,aa;//sum存该元素b中的位置,aa是a数组的位置,num存和
}teap[100001];
int fix()
{
int fa=1;
while (fa*2<=len-1)
{
int kk=fa*2;
if (kk+1<=len-1&&teap[kk].num>teap[kk+1].num) kk++;
if (teap[fa].num>teap[kk].num) {swap(teap[fa],teap[kk]);fa=kk;}
else break;
}
return t;
}
void put()
{
for (int i=1;i<=n;i++)
{
len++;
teap[len].num=a[i]+b[1];
teap[len].sum=1;
teap[len].aa=i;
fix();
}
}
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]);
sort(a+1,a+n+1);
sort(b+1,b+n+1);
memset(teap,127,sizeof(teap));
put();
int k=0;
for (int i=1;i<=n;i++)
{
k++;
answer[k]=teap[1].num;
teap[1].num=a[teap[1].aa]+b[teap[1].sum+1];
teap[1].sum++;
fix();
}
for (int i=1;i<=k;i++) printf("%d ",answer[i]);
}