P1631 序列合并

题目来源:洛谷

 

题目描述

 

有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2个和,求这N^2个和中最小的N个。

 

输入输出格式

 

输入格式:

 

 

 

第一行一个正整数N;

 

第二行N个整数AiAi+110^9Ai109;

 

第三行N个整数BiBi+110^9Bi109.

 

【数据规模】

 

对于50%的数据中,满足1<=N<=1000;

 

对于100%的数据中,满足1<=N<=100000。

 

 

 

输出格式:

 

 

 

输出仅一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。

 

 

 

输入输出样例

 

输入样例#1:
3
2 6 6
1 4 8
输出样例#1:
3 6 7

 

解析:

这题数学上讲不难,很容易想到解法根据题意,对于有序数列a和b,其最小和一定是a1+b1,次小和为min(a2+b1,b2+a1),如果次小和为a1+b2,那么第三小和就是min(a2+b1,a+b3,a2+b2),至于原因,我们知道an肯定比an-1大放到这里,因为次小和是a1+b2,所以,a2+b1的值是肯定比它要大的,而从它衍生出来的这两个值,就分别是an+1+bn和an+bn+1了因为他们是仅比a1+b2小的最大值。以此类推,我们得到可以得出本题的朴素解法。

优化是判重,由于(x,y+1)和(x+1,y)二者拓展出的解都覆盖了(x+1,y+1),我们只需要一个就好了,这样就可以的出遍历的唯一路径了。扎心的是,本蒟蒻STL的使用及其不成熟,重载运算符也不大会,而且其实貌似也不用自定义结构体的,但是我不会用优先队列,依葫芦画瓢写了个代码出来,思路虽然有,码不出来就很尴尬。。。其一,我们可以用pair将两个序列绑定,并用map判重;其二,我们可以只将某个数值的序号存入堆,取出时放到数组下标中加和就行了。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<ctime>
 6 #include<cstdlib>
 7 #include<algorithm>
 8 #include<queue>
 9 #include<set>
10 #include<map>
11 #define N 100010
12 using namespace std;
13 typedef pair<int,int> pp;
14 map<pp,bool> p;
15 int a[N],b[N];
16 struct node{
17     int i,j;
18     bool operator <(const node &t) const{
19         if(a[i]+b[j]<a[t.i]+b[t.j]) return false;
20         return true;
21     }
22     node(int x,int y){
23         i=x,j=y;
24     }
25 };
26 priority_queue<node> q;
27 int main()
28 {
29     int n;
30     scanf("%d",&n);
31     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
32     for(int i=1;i<=n;i++) scanf("%d",&b[i]);
33     q.push(node(1,1));
34     
35     for(int i=1;i<=n;i++)
36     {
37         while(p[make_pair(q.top().i,q.top().j)]) q.pop();
38         int xx=q.top().i;
39         int yy=q.top().j;
40         printf("%d ",a[xx]+b[yy]);
41         p[make_pair(q.top().i,q.top().j)]=true;
42         q.push(node(xx,yy+1));
43         q.push(node(xx+1,yy));
44     }
45     return 0;
46 }

2019-05-18 22:23:23



posted @ 2019-05-18 22:24  DarkValkyrie  阅读(229)  评论(0编辑  收藏  举报