思路来自题解
作者: 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=;
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=;i<=n;i++)scanf("%d",&a[i]);
for(int i=;i<=n;i++)scanf("%d",&b[i]);
for(int i=;i<=n;i++)q.push(node(a[i]+b[],i,));
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+],k1,k2+));
}
sort(ans+,ans++n);
for(int i=;i<=n;i++)printf("%d ",ans[i]);
}