zoukankan      html  css  js  c++  java
  • [luogu p2032] 扫描

    传送门

    扫描

    题目描述

    有一个 (1 imes n) 的矩阵,有 (n) 个整数。

    现在给你一个可以盖住连续 (k) 个数的木板。

    一开始木板盖住了矩阵的第 (1 sim k) 个数,每次将木板向右移动一个单位,直到右端与第 (n) 个数重合。

    每次移动前输出被覆盖住的数字中最大的数是多少。

    输入输出格式

    输入格式

    第一行两个整数 (n,k),表示共有 (n) 个数,木板可以盖住 (k) 个数。

    第二行 (n) 个整数,表示矩阵中的元素。

    输出格式

    (n - k + 1) 行,每行一个整数。

    (i) 行表示第 (i sim i + k - 1) 个数中最大值是多少。

    输入输出样例

    输入样例 #1

    5 3
    1 5 3 4 2
    

    输出样例 #1

    5
    5
    4
    

    说明

    对于 (20\%) 的数据,(1 leq k leq n leq 10^3)

    对于 (50\%) 的数据,(1 leq k leq n leq 10^4)

    对于 (100\%) 的数据,(1 leq k leq n leq 2 imes 10^6),矩阵中的元素大小不超过 (10^4) 并且均为正整数。

    分析

    暴力做法很容易想到 (mathcal{O}(nk)) 做法。但是这个做法实在是太暴力了,我们需要换单调队列做。

    定义一个双向队列 (q) 作为单调队列,其中 (q) 中每一个元素包含两个变量:元素的数值和元素的位置

    为什么要保存元素的位置呢?因为我们得实时监测当前的最大值所对应的位置是否还在当前的窗口。

    对于每一个元素,进行入队操作(同时也要维护这个单调队列),并检查当前单调队列的队首(最大值)的位置是否还在这个窗口,如果没在,我们需要弹出。然后输出当前队首的值即可。(单调队列的队首就是最大值了)。

    这种方法的时间复杂度是 (mathcal{O}(n)),可以说十分优秀了。

    核心代码如下:

        for (int i = 1; i <= n; ++i) {
            while (!q.empty() && q.back().first <= a[i])
                q.pop_back();
            q.push_back(std :: make_pair(a[i], i));
            if (q.front().second == i - k)
                q.pop_front();
            if (i >= k)
                std :: printf("%d
    ", q.front().first);
        }
    

    整体code如下:

    代码

    /*
     * @Author: crab-in-the-northeast 
     * @Date: 2020-10-17 19:04:13 
     * @Last Modified by: crab-in-the-northeast
     * @Last Modified time: 2020-10-17 20:28:32
     */
    #include <iostream>
    #include <cstdio>
    #include <utility>
    #include <deque>
    #include <functional>
    
    typedef std :: pair<int, int> Pair;
    
    std :: deque <Pair> q;
    
    const int maxn = 2000005;
    int a[maxn];
    
    int main() {
        int n, k;
        std :: scanf("%d %d", &n, &k);
        for (int i = 1; i <= n; ++i)
            std :: scanf("%d", &a[i]);
        
        for (int i = 1; i <= n; ++i) {
            while (!q.empty() && q.back().first <= a[i])
                q.pop_back();
            q.push_back(std :: make_pair(a[i], i));
            if (q.front().second == i - k)
                q.pop_front();
            if (i >= k)
                std :: printf("%d
    ", q.front().first);
        }
    
        return 0;
    }
    

    评测记录

    评测记录

  • 相关阅读:
    二叉树之求叶子结点个数
    求二叉树的深度
    二叉树的基本操作
    二叉树之求结点个数
    数组面试
    数组之求子数组的最大乘积
    字符串之子串
    最近遇到的几个纯C编程的陷阱
    Ubuntu 16.04 64位安装YouCompleteMe
    Linux和Windows的遍历目录下所有文件的方法对比
  • 原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p2032.html
Copyright © 2011-2022 走看看