思路来自题解
作者: Red_w1nE 更新时间: 2016-11-13 20:46 在Ta的博客查看
最近有点忙 没时间贴代码了==
【分析】
首先,把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]); }