zoukankan      html  css  js  c++  java
  • 2013多校第四场 B题

    题意:

      两个都含有N个元素的数组a,b, 求 a[i]+b[j] ( i , j < N ) 的前 M个最小值(M < N)

    解题思路:

      假定a,b数组都有序,则我们有下面的结论:

      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 的矩阵.如下形式

      A(1,1), A(1,2), ..., A(1,n)

      A(2,1), A(2,2), ... ,A(2,n)

      ...

      A(n,1), A(n,2), ... ,A(n,n)

      我们知道,第一个最小的必定是 A(1,1), 

      而且. 从 A(1,1) 位置往下(A(2,1)) 或者 往右(A(1,2)), 其值必定增大.

      但是我们又不知道 A(1,2) 与 A(2,1) 之间的关系.

      不过, 我们可以想到:

        若第k小的数是 A(i,j), 则第 k+1小的数可能是A(i+1,j)与A(i,j+1) 之间的数.

        因为还有可能是在 其他的 A( a,b ) 的下或者右中..

      又因为 我们只需要取前 M <= N 个数.所以我们使用一个容器,让里头保存N个数.

      每次从容器中取出一个最值( A(a,b) ), 则再将其下方( A(a+1,b) ),与右边( A(a,b+1) ) 的值放入容器中.  

      这个容器我们可以选 堆/优先队列: 

      直接用 C++的STL.  priority_queue< node, vector<node>, compare >  详细用法请百度.

    编码细节:

      我们可以预处理把 A(1,1), A(1,2), ...,A(1,n) 这N个数放到堆中, 每次取出最小的A(a,b)时,

      则只需要将 A(a+1,b) 加入到堆即可. 因为 A(a,b+1)已经在堆中了. 

      这样.始终维护着堆中包含N个元素. 当输出满足M个了就结束即可.

    算法时间复杂度:

      优先队列的 插入与删除操作都是 Log(N). 总共N个元素.

      则总体时间复杂度:  NlogN 

    View Code
    #include<cstdio>
    #include<cstdlib>
    #include<queue>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N = 4e5+10;
    
    int a[N], b[N], res[N];
    int n, m;
    struct Node{
        int x, y, v;
        bool operator < (const Node &tmp) const{
            return v > tmp.v;    
        }
    }node;
    priority_queue<Node> Q;
    
    int main(){
        freopen("1002.in","r",stdin);
        freopen("test.out","w",stdout);
        while( scanf("%d%d", &n, &m) != EOF){
            int cnt = 0;
            for(int i = 0; i < n; i++) scanf("%d", &a[i]);
            for(int i = 0; i < n; i++) scanf("%d", &b[i]);
            sort( a, a+n );
            sort( b, b+n );
            while( !Q.empty() ) Q.pop();
            for(int i = 0; i < n; i++){
                node.x = 0; node.y = i; node.v = a[0]+b[i];
                Q.push(node);
            }
            for(int i = 0; i < m; i++){
                node = Q.top(); Q.pop();
                printf("%d\n", node.v );
                node.x++; 
                node.v = a[ node.x ] + b[ node.y ];
                Q.push( node );
            }    
        }
        return 0;
    }
  • 相关阅读:
    20201220第二周学习总结
    师生关系
    快速浏览教材
    学期2020-2021-1学号20201220《信息安全专业导论》第1周学习总结
    编程将字符串s倒序输出,要求利用函数递归实现
    小学生四则运算随机生成程序
    礼炮问题
    C语言最大公约数
    C语言判断三角形类型
    C语言:一元二次方程解的所有情况
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3049498.html
Copyright © 2011-2022 走看看