洛谷 P1631 序列合并(优先队列)
传送门
解题思路
首先读入a、b数组后,sort一遍(从小到大),然后把a[1]+b[1],a[2]+b[1],a[3]+b[1]……a[n]+b[1]全部加入一个优先队列q(小根堆)。
然后从一到n循环,每一次取出队列中的最小的元素(假设是a[i]+b[j]),输出数值,然后把数值修改为a[i]+b[j+1],存入队列。
为什么呢?
很显然,我们把所有可能的情况列成一张表:
a[1]+b[1],a[2]+b[1],a[3]+b[1],……,a[n]+b[1];
a[1]+b[2],a[2]+b[2],a[3]+b[2],……,a[n]+b[2];
…………………………………………………………;
a[1]+b[n],a[2]+b[n],a[3]+b[n],……,a[n]+b[n]。
很显然,在这张表中,对于每一个数都一定小于它右下方的所有的数。
换一种说法,就是在第[i,j]个数为成为当前最小值时,它右下方的数不可能成为当前最小值。
所以只有在第[i,j]个数成为当前最小值时,把第[i+1][j]加入队列,继续比较。(也就是纵向更新)。
AC代码
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<queue> 5 using namespace std; 6 const int maxn=100005; 7 int n,a[maxn],b[maxn]; 8 struct node{ 9 int ans,bb; 10 bool operator < (const node &x)const{ 11 return ans>x.ans; 12 } 13 }; 14 priority_queue<node> q; 15 int main() 16 { 17 cin>>n; 18 for(int i=1;i<=n;i++) cin>>a[i]; 19 for(int i=1;i<=n;i++) cin>>b[i]; 20 sort(a+1,a+n+1); 21 sort(b+1,b+n+1); 22 for(int i=1;i<=n;i++){ 23 node x; 24 x.ans=a[i]+b[1]; 25 x.bb=1; 26 q.push(x); 27 } 28 for(int i=1;i<=n;i++){ 29 node now=q.top(); 30 q.pop(); 31 cout<<now.ans<<" "; 32 now.bb++; 33 now.ans=now.ans+b[now.bb]-b[now.bb-1]; 34 q.push(now); 35 } 36 return 0; 37 }