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_ileq 10^9\ Nleq 10^5 ]

分析

注意到问题可以转化为在一个(N imes 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);
	}
}
原文地址:https://www.cnblogs.com/hznumqf/p/13936599.html