有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2个和,求这N^2个和中最小的N个。
输入输出格式
输入格式:
第一行一个正整数N;
第二行N个整数Ai, 满足Ai≤Ai+1且Ai≤109
第三行N个整数Bi, 满足Bi≤Bi+1且Bi≤109
【数据规模】
对于50%的数据中,满足1<=N<=1000;
对于100%的数据中,满足1<=N<=100000。
输出格式:
输出仅一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。
输入输出样例
输入样例#1:
3 2 6 6 1 4 8
思路:这是一道挺遗憾的题,上学期参加外校邀请赛时出了这道题的变式,没A出来。赛后也没去追究(大一嘛,喜欢浪)。现在随缘跳题居然遇到了,这应该就是传说中的缘分了,那就嗑它。
数据范围暴力是不可能的,10^5,暗示时间复杂度需要nlogn,然而我这种弱鸡是不会算复杂度的,就顺着做呗。因为已知的序列都已经是有序的,完全暴力数据达到10^10,但我们只需要10^5,所以自然而然的就想到维护这个数据范围。以第一个数组+第二个数组第一个元素为初始状态,遍历第二个数组,每个组合加入时进行判断插入。这个实现可以用折半查找排序(维护范围可以减小复杂度),也可以使用堆排序来实现(不用管,反正只取前n个)。不会算复杂度也不知道二分会不会炸...
代码如下:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<set>
#include<string.h>
#include<queue>
#include<math.h>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define inf 0xf3f3f3f
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
using namespace std;
const int MAXBUF=10000;
char buf[MAXBUF],*ps=buf,*pe=buf+1;
inline void rnext()
{
if(++ps==pe)
pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);
}
template<class T>
inline bool in(T &ans)
{
ans=0;
T f=1;
if(ps==pe) return false;
do{
rnext();
if('-'==*ps) f=-1;
}while(!isdigit(*ps)&&ps!=pe);
if(ps==pe) return false;
do
{
ans=(ans<<1)+(ans<<3)+*ps-48;
rnext();
}while(isdigit(*ps)&&ps!=pe);
ans*=f;
return true;
}//输入挂
int a[100005],b[100005],s[100005];
//priority_queue<int,vector<int>,greater<int>>q;
priority_queue<int>q;//最大堆
int main()
{
std::ios::sync_with_stdio(false);
int n;
in(n);
per(i,1,n)
in(a[i]);
per(i,1,n)
{
in(b[i]);
if(i==1) per(j,1,n) q.push(b[1]+a[j]);
else
{
per(j,1,n)
{
int z=q.top();//出n个数最大的
if(a[j]+b[i]>=z) break;//因为ab数组都是有序的,所以后面的是肯定大于直接跳过
q.pop();
q.push(a[j]+b[i]);//自动实现排序
}
}
}
per(i,1,n) //只取前n个
{
s[i]=q.top();
q.pop();
}
rep(i,n,1) printf("%d",s[i]);
return 0;
}