题解 P1631 【序列合并】

· · 题解

首先声明,我想发题解是因为我觉得我的代码最短、最简洁,并运用了将两个优先队列绑定起来的数据结构(pair)。

这道题和果子合并非常像,每次都是取2个最小的数,但是本题中每个数可以取多次,但是数对不能重复,但是算法还是一样的,利用优先队列.

由于本题中的数据已经排好序了,所以如果选取了坐标为i,j的两个数,那么下一次可能选i+1,j或i,j+1,这样的话由于每个数可以取多次容易重复,所以使用SET判重,这样的话由于要使用两个结构体,比较容易写错.

还有一种比较简单的方式,首先不管怎么样,A序列中的第一个数绝对要选,那么这个数可能和B序列中的任何一个数组成的数对被选,全部加入优先队列中,这样处理了i,j+1的情况,但是还有i+1,j的情况,每次输出一个和之后,将B序列中的第i个数对应的A序列中的第j个数的j++.

但是这样数对还是容易重复,怎么办呢?可以用一个数组记录一下,to[i]表示B序列中的第i个数与A序列中的第几个数相加,每次入队的时候累加to数组就不会造成重复了!

#include<cstdio>  
#include<queue>   
using namespace std;
int a[100005]={}, b[100005]={}, to[100005]={},i, n;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > >q;
int main()
{
    scanf("%d", &n);
    for (i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for (i = 1; i <= n; i++)
    {
        scanf("%d", &b[i]); to[i] = 1;
        q.push(pair<int, int>(a[1] + b[i], i));
    }
    while (n--)
    {
        printf("%d ", q.top().first);
        i = q.top().second; q.pop();
        q.push(pair<int, int>(a[++to[i]] + b[i], i));
    }
    return 0;
}