wikioi 1245 最小的N个和

来源:互联网 发布:网络出版物服务许可证 编辑:程序博客网 时间:2024/05/21 08:57

题目链接:wikioi 1245

 

题目大意:

         有两个长度为 N(1≤N≤100000) 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N2个和,求这N2 个和中最小的 N个。

 

题目分析:

         对于任意Ai+Bi可得到N2个和,对这些和进行如下分类,可写成:

                   A1+B1,A1+B2, A1+B3 …… A1+Bn

                   A2+B1,A2+B2, A2+B3 …… A2+Bn

                   A3+B1,A3+B2, A3+B3 …… A3+Bn

                   ……

                   An+B1,An+B2, An+B3 …… An+Bn

         如果对A和B进行排序后,就会发现:Ai+ Bj≤Ai+1 + Bj+1,也就是上面的每一行从左到右是依次递增的序列,每一列从上到下也是递增序列。由此,我们可以把每一行看作是一个有序序列,然后对所有序列进行n次n路归并就可以得到这前n2个数中的最小的n个。

 

代码:

#include <stdio.h>#include <stdlib.h>#define maxn 100005#define sum(i) (A[a[i]] + B[b[i]])int n;int a[maxn], b[maxn];int A[maxn], B[maxn];int cmp(const void* a, const void* b) {return *(int*)a - *(int*)b;}inline void update() {int i = 1, j = 2;a[0] = a[1], b[0] = b[1] + 1;while (j <= n) {if (j < n && sum(j + 1) < sum(j))j++;if (sum(0) < sum(j))break;a[i] = a[j], b[i] = b[j];i = j; j <<= 1;}a[i] = a[0], b[i] = b[0];}int main() {int i;scanf("%d", &n);for (i = 1; i <= n; i++)scanf("%d", &A[i]);for (i = 1; i <= n; i++)scanf("%d", &B[i]);qsort(A + 1, n, sizeof(int), cmp);qsort(B + 1, n, sizeof(int), cmp);for (i = 1; i <= n; i++)a[i] = i, b[i] = 1;for (i = 1; i <= n; i++) {printf("%d ", sum(1));update();}return 0;}


原创粉丝点击