洛谷P1631 序列合并

传送门

Solution:

首先将 a a a b b b数组分别排序。
原理:对于每个 i i i a i + b i < = a i + b i + 1 < = . . < = a i + b N a_i + b_i <= a_i + b_{i+1} <= .. <= a_i + b_N ai+bi<=ai+bi+1<=..<=ai+bN
流程:

  • 对于每个 i i i,初始化时将不等式打头的那个扔进优先队列。
  • 取出最小值,弹出,然后将该不等式“所在位置”的后一位扔进优先队列。
    如取出的值是 a 3 + b 5 a_3 + b_5 a3+b5,接下来应将 a 3 + b 6 a_3 + b_6 a3+b6扔进优先队列。
    注意当取出的值为 a x + b x a_x + b_x ax+bx时,应将 a x + 1 + b x , a x + b x + 1 a_{x+1} + b_x,a_x + b_{x+1} ax+1+bx,ax+bx+1扔进优先队列。
  • 重复步骤2,直到取出 N N N次。

code:

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXN = 100007;
int N;
struct Node {
	int x, y, sum; // A中元素的标号,B中元素的标号,两个标号对应的值之和
	Node (int x = 0, int y = 0, int sum = 0) : x(x), y(y), sum(sum) {}
	bool operator < (const Node h) const {return sum > h.sum;}
};
int A[MAXN], B[MAXN];
int tota[MAXN], totb[MAXN];
priority_queue <Node> Q;

int main() {
	#ifdef test
		freopen("test.txt", "r", stdin);
	#endif
	cin >> N;
	for(int i = 1; i <= N; i++)
		scanf("%d", &A[i]);
	for(int i = 1; i <= N; i++)
		scanf("%d", &B[i]);
	sort(A + 1, A + N + 1);
	sort(B + 1, B + N + 1);
	
	for(int i = 1; i <= N; i++) {
		tota[i] = totb[i] = i;
		Q.push(Node(i, i, A[i] + B[i]));
	}
	
	for(int i = 1; i <= N; i++) {
		Node h = Q.top(); Q.pop();
		int x = h.x, y = h.y;
		printf("%d ", h.sum);
		if(x < y)
			if(tota[x] < N)
				++tota[x], Q.push(Node(x, tota[x], A[x] + B[tota[x]]));
		if(x == y) {
			if(tota[x] < N)
				++tota[x], Q.push(Node(x, tota[x], A[x] + B[tota[x]]));
			if(totb[y] < N)
				++totb[y], Q.push(Node(totb[y], y, B[y] + A[totb[y]]));
		}
		if(x > y)
			if(totb[y] < N)
				++totb[y], Q.push(Node(totb[y], y, B[y] + A[totb[y]]));
	}
	return 0;
}
posted @ 2020-11-03 23:00  Speculator18  阅读(62)  评论(0)    收藏  举报