[题解](堆)luogu_P1631序列合并

思路来自题解

作者: Red_w1nE 更新时间: 2016-11-13 20:46  在Ta的博客查看  72 


最近有点忙 没时间贴代码了==

【分析】

首先,把A和B两个序列分别从小到大排序,变成两个有序队列。这样,从A和B中各任取一个数相加得到N^2个和,可以把这些和看成形成了n个有序表/队列:

A[1]+B[1] <= A[1]+B[2] <= … <= A[1]+B[N]

A[2]+B[1] <= A[2]+B[2] <= … <= A[2]+B[N]

……

A[N]+B[1] <= A[N]+B[2] <= … <= A[N]+B[N]

接下来,就相当于要将这N个有序队列进行合并排序:

首先,将这N个队列中的第一个元素放入一个堆中;

然后;每次取出堆中的最小值。若这个最小值来自于第k个队列,那么,就将第k个队列的下一个元素放入堆中。

时间复杂度:O(NlogN)。

priority_queue<int, vector<int>,greater<int> > q;

分析过程可能是这样的:事实上我们不需要把所有的a[i]和b[i]的和全部存下来,因为序列的单调性,所以我们先用a中的最小值和其他b中所有值加起来

对于每个b[i]来说都一定是当前对应最小的值,所以对b[i]来说,其他和b[i]不对应的a目前不会成为答案,也就没必要把他们加到堆里

当当前这个用过后,下一个a就有可能成为答案了,所以再把下一个a加进堆

不同的理解方法吧

题解中还有用二分做的

类似的题:luogu_P2085最小函数值

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int n,a[maxn],b[maxn];
struct node{
    int x,k1,k2;
    node(int xx,int kk1,int kk2){
        x=xx,k1=kk1,k2=kk2;
    }
    bool operator <(const node &a)const{
        return x>a.x;
    }
};
priority_queue<node>q;
int ans[maxn],cnt;
int main(){
    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]);
    for(int i=1;i<=n;i++)q.push(node(a[i]+b[1],i,1));
    while(cnt<=n){
        int x=q.top().x,k1=q.top().k1,k2=q.top().k2;q.pop();
        ans[++cnt]=x;
        q.push(node(a[k1]+b[k2+1],k1,k2+1));
    }
    sort(ans+1,ans+1+n);
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
}

 

posted @ 2019-04-26 21:03  羊肉汤泡煎饼  阅读(119)  评论(0编辑  收藏  举报