zoukankan      html  css  js  c++  java
  • poj 2823 Sliding Windows (单调队列+输入输出挂)

    Sliding Window
    Time Limit: 12000MS   Memory Limit: 65536K
    Total Submissions: 73426   Accepted: 20849
    Case Time Limit: 5000MS

    Description

    An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example: 
    The array is [1 3 -1 -3 5 3 6 7], and k is 3.
    Window positionMinimum valueMaximum value
    [1  3  -1] -3  5  3  6  7  -1 3
     1 [3  -1  -3] 5  3  6  7  -3 3
     1  3 [-1  -3  5] 3  6  7  -3 5
     1  3  -1 [-3  5  3] 6  7  -3 5
     1  3  -1  -3 [5  3  6] 7  3 6
     1  3  -1  -3  5 [3  6  7] 3 7

    Your task is to determine the maximum and minimum values in the sliding window at each position. 

    Input

    The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line. 

    Output

    There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values. 

    Sample Input

    8 3
    1 3 -1 -3 5 3 6 7
    

    Sample Output

    -1 -3 -3 -3 3 3
    3 3 5 5 6 7

    题目大意:

    给你长度为n的数列,要你输出1..k, 2..k+1, 3..k+2, ...区间的最大值和最小值。

    单调队列经典题。

    维护单调不减序列和单调不增序列的下标,这样队首就分别是最小值和最大值的下标。

    以单调不减序列举例:

    每次向后移动,先删除队尾元素直至小于等于新元素。贪心的思想,之前队尾元素如果比它大,那该队尾元素永远不可能成为某个区间的最小值。

    再判断队首元素是否在k区间内。

    单调不增序列同理。

    单调队列可以用deque写。

    对这两个队列考虑,(平摊分析)每个元素最多入队出队两次。复杂度O(n)。

    所以TLE总是让人觉得僵硬。On, 1e6, T???

    其实是io太慢了。

    scanf printf 相对cin cout 来说确实快了,但这个可是1e6+2e6啊 。。 ̄へ ̄

    第一次真正明白输入输出挂的含义。

    scanf printf 其实就是对putchar getchar 等函数的封装,功能强大但臃肿。所以,要用一些速度比scanf快,但功能比putchar全面的函数取而代之。

    输入输出挂(正负整数)。

    template <class T>
    inline bool scan_d(T &ret)
    {
        char c;
        int sgn;
        if (c = getchar(), c == EOF)
        {
            return 0; //EOF
        }
        while (c != '-' && (c < '0' || c > '9'))
        {
            c = getchar();
        }
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while (c = getchar(), c >= '0' && c <= '9')
        {
            ret = ret * 10 + (c - '0');
        }
        ret *= sgn;
        return 1;
    }
    
    template <class T>
    inline void print_d(T x)
    {
        if(x < 0)
        {
            putchar('-'); x = -x;
        }
        if (x > 9)
        {
            print_d(x / 10);
        }
        putchar(x % 10 + '0');
    }
    View Code

    由上面的代码可以看出,输出一个整数的复杂度并不是o1的,取决于输出数的位数,是o(m),m是常数。如果数是int,n又很大(1e6),复杂度其实是o(mn),用printf的话可以当成onlogn+算了,t也不奇怪吧。

    不过该挂对C++极度无感(不知道为啥。。),对G++就很真实了。从下图来说,scanf用c++会快一点,不过真遇到大量输出,g++&挂是最佳选择,所以忘了c++吧。

     AC代码:

    #include <cstdio>
    #include <queue>
    #include <deque>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    typedef long long ll;
    const int maxn=1000000;
    
    template <class T>
    inline bool scan_d(T &ret)
    {
        char c;
        int sgn;
        if (c = getchar(), c == EOF)
        {
            return 0; //EOF
        }
        while (c != '-' && (c < '0' || c > '9'))
        {
            c = getchar();
        }
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while (c = getchar(), c >= '0' && c <= '9')
        {
            ret = ret * 10 + (c - '0');
        }
        ret *= sgn;
        return 1;
    }
    
    template <class T>
    inline void print_d(T x)
    {
        if(x < 0)
        {
            putchar('-'); x = -x;
        }
        if (x > 9)
        {
            print_d(x / 10);
        }
        putchar(x % 10 + '0');
    }
    
    int arr[maxn+5];
    int temp[maxn+5];
    int ans[maxn][2];
    
    int cmp(int x,int y)
    {
        return arr[x]<arr[y];
    }
    
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scan_d(arr[i]);
    
        std::deque<int> incq;//单调不减序列
        std::deque<int> decq;//单调不增序列
    
        for(int i=1;i<=k;i++)
            temp[i]=i;
        std::sort(temp+1,temp+1+k,cmp);
        for(int i=1;i<=k;i++)
        {
            incq.push_back(temp[i]);
            decq.push_front(temp[i]);
        }
        ans[1][0]=arr[incq.front()];
        ans[1][1]=arr[decq.front()];
    
        for(int i=k+1;i<=n;i++)
        {
            while(!incq.empty())
            {
                if(incq.front()+k-1<i)
                    incq.pop_front();
                else
                    break;
            }
            while(!incq.empty())
            {
                if(arr[incq.back()]>arr[i])
                    incq.pop_back();
                else
                    break;
            }
            incq.push_back(i);
            while(!decq.empty())
            {
                if(decq.front()+k-1<i)
                    decq.pop_front();
                else
                    break;
            }
            while(!decq.empty())
            {
                if(arr[decq.back()]<arr[i])
                    decq.pop_back();
                else
                    break;
            }
            decq.push_back(i);
            ans[i-k+1][0]=arr[incq.front()];
            ans[i-k+1][1]=arr[decq.front()];
        }
    
        for(int i=1;i<=n-k+1;i++)
        {
            if(i==1)
                print_d(ans[i][0]);
            else
            {
                putchar(' ');
                print_d(ans[i][0]);
            }
        }
        putchar('
    ');
        for(int i=1;i<=n-k+1;i++)
        {
            if(i==1)
                print_d(ans[i][1]);
            else
            {
                putchar(' ');
                print_d(ans[i][1]);
            }
        }
        putchar('
    ');
    
        return 0;
    }
    View Code
  • 相关阅读:
    [计算机网络-传输层] 无连接传输:UDP
    [BinaryTree] 最大堆的类实现
    [OS] 生产者-消费者问题(有限缓冲问题)
    [剑指Offer] 64.滑动窗口的最大值
    [剑指Offer] 63.数据流中的中位数
    [剑指Offer] 62.二叉搜索树的第k个结点
    [OS] CPU调度
    [剑指Offer] 60.把二叉树打印成多行
    MySQL数据库实验二:单表查询
    数据库实验:基本表的定义与修改
  • 原文地址:https://www.cnblogs.com/acboyty/p/9975881.html
Copyright © 2011-2022 走看看