• BZOJ 1047 二维单调队列


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1047

    题意:见中文题面

    思路:该题是求二维的子矩阵的最大值与最小值的差值尽量小。所以可以考虑求出每个子矩阵的最大值和最小值。考虑一维求子段的最小值/最大值的思路。滑动窗口+单调队列。 转换成二维。设minNum[i][j]表示右下角为(i,j)的子矩阵的最小值。先对矩阵每一行用一维的做法求出每一行的子段的最小值,然后同样的方法求列的最值。注意在求列的子段最小值时比较的元素不是原矩阵的元素而是用行求的结果来比较。 具体看代码吧。

    #define _CRT_SECURE_NO_DEPRECATE
    #include<stdio.h>  
    #include<string.h>  
    #include<cstring>
    #include<algorithm>  
    #include<queue>  
    #include<math.h>  
    #include<time.h>
    #include<vector>
    #include<iostream>
    #include<string>
    using namespace std;
    typedef long long int LL;
    const int MAXN = 1000 + 10;
    const int INF = 0x3f3f3f3f;
    int n, m, k, num[MAXN][MAXN], minNum[MAXN][MAXN], maxNum[MAXN][MAXN];
    void solve(int type, int seg[][MAXN]){
        deque<pair<int, int> > deq;
        for (int i = 1; i <= n; i++){ //求行子段的最值。
            deq.clear();
            for (int j = 1; j <= m; j++){
                while (!deq.empty() && j - deq.front().second >= k){ deq.pop_front(); }
                if (type){
                    while (!deq.empty() && deq.back().first < num[i][j]){ deq.pop_back(); }
                }
                else{
                    while (!deq.empty() && deq.back().first > num[i][j]){ deq.pop_back(); }
                }
                deq.push_back(make_pair(num[i][j], j));
                seg[i][j] = deq.front().first;
            }
        }
        for (int j = 1; j <= m; j++){ //求列的最值
            deq.clear();
            for (int i = 1; i <= n; i++){
                while (!deq.empty() && i - deq.front().second >= k){ deq.pop_front(); }
                if (type){
                    while (!deq.empty() && deq.back().first < seg[i][j]){ deq.pop_back(); }
                }
                else{
                    while (!deq.empty() && deq.back().first > seg[i][j]){ deq.pop_back(); }
                }
                deq.push_back(make_pair(seg[i][j], i));
                seg[i][j] = deq.front().first;
            }
        }
    }
    int main(){
    //#ifdef kirito
    //    freopen("in.txt", "r", stdin);
    //    freopen("out.txt", "w", stdout);
    //#endif
    //    int start = clock();
        while (~scanf("%d%d%d", &n, &m, &k)){
            for (int i = 1; i <= n; i++){
                for (int j = 1; j <= m; j++){
                    scanf("%d", &num[i][j]);
                }
            }
            int ans = INF;
            solve(0, minNum); solve(1, maxNum);
            ////Debug
            //printf("minNum Segment:
    ");
            //for (int i = 1; i <= n; i++){
            //    for (int j = 1; j <= m; j++){
            //        printf("%d ", minNum[i][j]);
            //    }
            //    printf("
    ");
            //}
            //printf("maxNum Segment:
    ");
            //for (int i = 1; i <= n; i++){
            //    for (int j = 1; j <= m; j++){
            //        printf("%d ", maxNum[i][j]);
            //    }
            //    printf("
    ");
            //}
            for (int i = k; i <= n; i++){
                for (int j = k; j <= m; j++){
                    ans = min(ans, maxNum[i][j] - minNum[i][j]);
                }
            }
            printf("%d
    ", ans);
        }
    //#ifdef LOCAL_TIME
    //    cout << "[Finished in " << clock() - start << " ms]" << endl;
    //#endif
        return 0;
    }
  • 相关阅读:
    算法(一)—— 河内之塔(汉诺塔)
    JAVA爬取网页邮箱
    js中判断某字符串含有某字符出现的次数
    逻辑删除和物理删除的区别
    Forward和Redirect的区别
    Postman 传Map类型的参数
    Java基础
    【html-css】
    【HTML----】
    【python-while-以及字符串的相关操作和函数】
  • 原文地址:https://www.cnblogs.com/kirito520/p/6098562.html
Copyright © 2020-2023  润新知