题目描述 Description
有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。
第一行输入一个正整数N;第二行N个整数Ai 且Ai≤10^9;第三行N个整数Bi,
且Bi≤10^9
输出仅一行,包含 n 个整数,从小到大输出这 N个最小的和,相邻数字之间用
空格隔开。
5
1 3 2 4 5
6 3 4 1 7
2 3 4 4 5
题目思路:【数据规模】 对于 100%的数据,满足 1≤N≤100000。
本题是《训练指南》第189面的题的变种(原题比此题更难),原理上来说其实不难,但是由于本题范围太大,单纯使用数组必定会MLE,因此需要借助二叉堆,二叉堆的元素用结构体定义为node,为了节约空间,node结构体中不必包含a值,只需包含sum和b的值,a的值可以通过sum和b求出,但在使用时同样要注意不能MLE,怎么办呢?先把数组a[],b[]降序排序,从0~n对a[i]+b[0]求和入堆,再从堆顶开始,对堆中每个元素的b值进行判断,只要b<n,就表明某个元素的b值为b+1是存在的,又由于二叉堆是最大化堆,数组也是降序的,a[i]+b[j+1]>a[i]+b[j]必然成立,将元素{sum,b[j]}出堆,将{sum',b[j+1]}入堆,这样就能节约空间,不至于MLE了,本题充分考察了对二叉堆特性的应用,是一道很经典的题目。
#include <stdio.h> #include <queue> #include <algorithm> #define MAXN 100005 using namespace std; struct node { int sum,b; bool operator < (node a) const { return sum>a.sum; } }heap[MAXN*2]; priority_queue<node> q; int cmp(int x,int y) { return x<y; } int main() { int n,i,j,in,a[MAXN],b[MAXN]; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d",&a[i]); } for(i=0;i<n;i++) { scanf("%d",&b[i]); } sort(a,a+n,cmp); sort(b,b+n,cmp); for(i=0;i<n;i++) q.push((node) {a[i] + b[0], 0}); for(i=0;i<n;i++) { node buf=q.top(); //将堆顶的元素buf(sum,b)取出 q.pop();//出堆 printf("%d ",buf.sum); if(buf.b<n) //如果元素buf的b<n的话,表明还可以得到元素x={sum+1,b+1},将它压入堆中 q.push((node){buf.sum-b[buf.b]+b[buf.b+1],buf.b+1}); } printf("\n"); return 0; }