zoukankan      html  css  js  c++  java
  • Day1-Luogu-1631

    题目描述

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

    输入输出格式

    输入格式:

    第一行一个正整数N;

    第二行N个整数A_iAi, 满足A_ile A_{i+1}AiAi+1A_ile 10^9Ai109;

    第三行N个整数B_iBi, 满足B_ile B_{i+1}BiBi+1B_ile 10^9Bi109.

    【数据规模】

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

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

    输出格式:

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

    输入输出样例

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

    思路:朴素做法的复杂度不可取,那么取完前3N个肯定有前N个的答案,代码如下:
    const int maxm = 100002;
    
    int a[maxm], b[maxm];
    
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d", &a[i]);
        for (int i = 0; i < n; ++i)
            scanf("%d", &b[i]);
        priority_queue<int, vector<int>, greater<int>> q;
        int l = 0, r = 0;
        q.push(a[l] + b[r]);
        while(q.size() <= 3 *n) {
            if(a[l] <= b[r]) {
                l++;
                if(l >= n)
                    break;
                for (int i = 0; i <= r; ++i)
                    q.push(a[l] + b[i]);
            } else {
                r++;
                if(r >= n)
                    break;
                for (int i = 0; i <= l; ++i)
                    q.push(a[i] + b[r]);
            }
        }
        for (int i = 0;i < n; ++i) {
            if(i)
                printf(" ");
            printf("%d", q.top());
            q.pop();
        }
        return 0;
    }
    View Code

     看完别人的解析后,懂了一种新的做法,图示:

      a1 a2 a3 a4 a5
    b1          
    b2          
    b3          
    b4          
    b5          

    此时N = 5, 若a3+b2是前N小,那么从a1+b1前面都是前N小,但其前面已经有N个了,则a3+b2不可能是前N小,即:(i-1)*(j-1) > N的点不可能产生贡献,代码如下:

    const int maxm = 100002;
    
    int a[maxm], b[maxm];
    
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d", &a[i]);
        for (int i = 0; i < n; ++i)
            scanf("%d", &b[i]);
        priority_queue<int, vector<int>, greater<int>> q;
        for(int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if(i * j > n)
                    break;
                q.push(a[i] + b[j]);
            }
        }
        for (int i = 0;i < n; ++i) {
            if(i)
                printf(" ");
            printf("%d", q.top());
            q.pop();
        }
        return 0;
    }
    View Code

     还有一种通用的合并队列最小值做法,因为a[1]+b[1]<=a[2]+b[1]<= ······ 这时候将所有的含有b[1]的压入队列,将最小的出队,例如,此时出队的是a[5]+b[1],那么下次入队的就是a[5]+b[2],且此时的a[5]+b[2]比任何还未入队的元素都大,循环往复找到N个即可,代码如下:

    const int maxm = 100002;
    
    struct Node{
        int sum, ia, ib;
        Node(int _sum, int _ia, int _ib):sum(_sum), ia(_ia), ib(_ib) {}
        bool operator < (const Node &a)const {
            return a.sum < sum;
        }
    };
    
    int a[maxm], b[maxm];
    
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d", &a[i]);
        for (int i = 0; i < n; ++i)
            scanf("%d", &b[i]);
        priority_queue<Node> q;
        for (int i = 0; i < n; ++i) {
            q.push(Node(a[i] + b[0], i, 0));
        }
        while(n--) {
            Node tmp = q.top();
            q.pop();
            printf("%d ", tmp.sum);
            q.push(Node(a[tmp.ia] + b[tmp.ib + 1], tmp.ia, tmp.ib + 1));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    B-S 期权定价模型
    可转债溢价率
    队列模拟递归遍历目录(广度遍历)
    栈模拟递归遍历目录(深度遍历)
    什么人适合学习Django?
    Python学习笔记———递归遍历多层目录
    树莓派开机自启动程序的设置,两步即可。
    7行代码对百万张照片统一改名。
    tornado上帝视角第一次建立WEB服务器
    武沛齐模态对话框课堂作业
  • 原文地址:https://www.cnblogs.com/GRedComeT/p/11215760.html
Copyright © 2011-2022 走看看