P1631 序列合并(堆排序)

有两个长度都是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;
} 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值