有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2个和,求这N^2个和中最小的N个。
输入格式:
第一行一个正整数N;
第二行N个整数Ai?≤Ai+1?且10^9Ai?≤109;
第三行N个整数Bi?≤Bi+1?且10^9Bi?≤109.
【数据规模】
对于50%的数据中,满足1<=N<=1000;
对于100%的数据中,满足1<=N<=100000。
输出格式:
输出仅一行,包含N个整数,从小到大输出这N个最小的和,相邻数字之间用空格隔开。
3 2 6 6 1 4 8
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
原文:https://www.cnblogs.com/DarkValkyrie/p/10887420.html