题目描述
问题:序列和的前n小元素
给出两个长度为n的有序表A和B, 在A和B中各任取一个, 可以得到 n^2 个和. 求这些和最小的n个。
输入输出格式
输入格式:
输入数据共三行。
第一行,一个整数值n ( n <= 10^4 )。
第二,第三行,各有n个从小到大排好序的整数,每个整数间有一个空格间隔。(每个整数均小于2^30)
输出格式:
输出数据一行,这些和最小的n个数,从小到大输出,每个整数之间一个空格间隔。
输入输出样例
输入样例#1:
3
2 6 6
1 4 8
输出样例#1:
3 6 7
思路
我刚看到这题的时候还以为是到水题,不就是给 n 2 n^2 n2个数排个序然后输出吗?结果花两分钟写完代码然后直接TLE…
然后听了一下老师的评讲,发现确实是一道水题
思路大概就是:
1.建一个大根堆(优先队列)来维护a数组和b数组的和
!!!是大根堆不是小根堆!!!不要看它是从小到大排序就建小根堆因为大根堆的堆顶是最大的,相当于一个守门员,所有数想要进堆就必须经过它。我们可以借助这个堆顶来筛选所有数字。
2.双重循环暴力枚举a数组和b数组的和,但!!!这里可以剪枝!!!由于输入的是两个有序表,所以只要有一个加出来的和比大根堆的堆顶大,那么后面加出来的和会比大根堆的堆顶更大,是不可能入得了堆的。所以直接break就行啦
3.将比堆顶小的a数组和b数组的和放入堆中
4.这时我们可以得到一个从大到小的队列(大顶堆),最后倒过来输出一下就AC啦
如果没看懂就看看代码和注释吧:
AC代码
#include<bits/stdc++.h>
using namespace std;
int n,t,a[100001],ans,b[100001],c[100001];
map<int,int> p;
priority_queue <int,vector<int>,less<int> > q;//从大到小
//priority_queue <int,vector<int>,greater<int> > q1;//从小到大
int main(){cin>>n;for(int i=1;i<=n;i++){//输入 cin>>a[i];}for(int i=1;i<=n;i++){//先将a[1]+b[1...n]放入队列 cin>>b[i];q.push(a[1]+b[i]);}for(int i=2;i<=n;i++){//枚举 for(int j=1;j<=n;j++){if(a[i]+b[j]>q.top()) break;//由于b是一个有序表,所以如果当前这个都大了那么后面的会更大 ,所以可以直接break q.pop();//弹出最大的 q.push(a[i]+b[j]);//放入新的数 }}//这时得到了一个大顶堆,我不知道怎样倒过来,所以用了最笨的方法,如果有更好的方法欢迎评论区讨论哦int i=0;while(!q.empty()){//倒过来i++;c[i]=q.top();q.pop();}for(int j=i;j>=1;j--) cout<<c[j]<<" ";//输出return 0;
}
这题这样就过啦,记得三连支持一下哦QAQ