luogu1631 序列合并

题目大意

  有两个序列A,B,在A和B中各取一个数相加能得到$n^2$个和。求出这些和前n小的数字。

题解

  首先这道题不可以用自己想的什么A序列B序列各两个指针的自己发明的模拟算法,用这样的算法只能是绝路一条。

  此题入手点在于优化暴力。暴力算法是枚举所有的$A_i+B_j$,排个序,然后一个个输出。我们优化之处便是如何动态枚举$A_i,B_j$。

  此时我曾想对两个数组都动态,这样想就走到了死胡同。

  我们可以让A不动态,B动态,也就是优先队列里储存的数对里包含所有的$A_i$,但每个$A_I$只对应一个$B_j$。每次出队时,将$A_i$对应的$B_j$的j++再推入队列中。这样便有解了。

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

const int MAX_N = 100010, INF = 0x3f3f3f3f;
int A[MAX_N], B[MAX_N];

struct Element
{
    int AId, BId;
    
    Element(int aId, int bId):AId(aId), BId(bId){}
    
    bool operator < (const Element a) const
    {
        return A[AId] + B[BId] > A[a.AId] + B[a.BId];
    }
};
priority_queue<Element> q;

int main()
{
    int n;
    scanf("%d", &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++)
        q.push(Element(i, 1));
    for (int i = 1; i <= n; i++)
    {
        Element cur = q.top();
        q.pop();
        printf("%d ", A[cur.AId] + B[cur.BId]);
        if (cur.BId < n)
        {
            cur.BId++;
            q.push(cur);
        }
    }
    return 0;
}

  

posted @ 2018-08-09 17:53  headboy2002  阅读(107)  评论(0编辑  收藏  举报