Loading

P1631 序列合并 思维 堆优化

P1631 序列合并 思维 堆优化

题意

有两个长度都是\(N\)的序列\(A\)\(B\),在\(A,B\)中各取一个数相加共可以得到\(N^2\)个和,求出这\(N ^ 2\)个和中最小的\(N\)

\[A_i \leq A_{i+1},A_i \leq 10^9\\ B_i \leq B_{i+1},B_i\leq 10^9\\ N\leq 10^5 \]

分析

注意到问题可以转化为在一个\(N \times N\)的矩阵中选择\(N\)个最小的元素

注意到这个矩阵的特点,从左到右以及从上到下都是递增的,因此每次选择实际上都是只在有限个数中选取

维护一列数,若其中某个数是最小的则弹出,加入这个数的下一列数

显然维护的第一列数是可以是第一列

因此可以用堆来维护

代码用用负数push,可以不用写比较函数

时间复杂度\(O(nlogn)\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;

ull readull(){
	ull x = 0;
	int f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar(); 
	}
	while(ch >= '0' && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f * x;
}
int readint(){
	int x = 0;
	int f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar(); 
	}
	while(ch >= '0' && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f * x;
}

#define pii pair<int,int>
#define fi first
#define se second
const int maxn = 1e5 + 5;

int a[maxn];
int b[maxn];
int cur[maxn];
priority_queue<pii> q; 

int main(){
	int n = readint();
	for(int i = 1;i <= n;i++)
		a[i] = readint();
	for(int i = 1;i <= n;i++)
		b[i] = readint();
	for(int i = 1;i <= n;i++)
		q.push(make_pair(-(a[1] + b[i]),i));
	for(int i = 1;i <= n;i++){
		pii now = q.top();
		cur[now.se]++;
		q.pop();
		q.push(make_pair(-(a[1 + cur[now.se]] + b[now.se]),now.se));
		printf("%d ",-now.fi);
	}
}
posted @ 2020-11-06 14:08  MQFLLY  阅读(125)  评论(0编辑  收藏  举报