soj 3636 理想的正方形(二维单调队列)

@(K ACMer)

题意:
求大矩阵中,所有 nn 子矩阵中最大数和最小数差的最小值.
分析:
查连续的固定长度的区间的最值是单调队列的经典应用.这里只需要按行求出所有固定区间的最值,在把这些最值来按列用单调队列求出最值即可.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod = int(1e9) + 7, INF = 0x3fffffff, maxn = 1e3 + 40;
int n, m, a[maxn][maxn], b[maxn][maxn], c[maxn][maxn];
int ans, k, diq[3 * maxn], ddq[3 * maxn];

void doit(void) {
    for (int i = 1; i <= n; i++) {
        int si = 0, sd = 0, ei = 0, ed = 0;
        for (int j = 1; j <= m; j++) {
            while (si < ei && a[i][diq[ei - 1]] > a[i][j]) ei--;
            diq[ei++] = j;
            while (sd < ed && a[i][ddq[ed - 1]] < a[i][j]) ed--;
            ddq[ed++] = j;
            if (j - k >= diq[si]) si++;
            if (j - k >= ddq[sd]) sd++;
            b[i][j] = a[i][diq[si]];
            c[i][j] = a[i][ddq[sd]];
        }
    }
}

void gotit(void) {
    for (int i = k; i <= m; i++) {
        int si = 0, sd = 0, ei = 0, ed = 0;
        for (int j = 1; j <= n; j++) {
            while (si < ei && b[diq[ei - 1]][i] > b[j][i]) ei--;
            diq[ei++] = j;
            while (sd < ed && c[ddq[ed - 1]][i] < c[j][i]) ed--;
            ddq[ed++] = j;
            if (j - k >= diq[si]) si++;
            if (j - k >= ddq[sd]) sd++;
            if (j >= k) ans = min(ans, c[ddq[sd]][i] - b[diq[si]][i]);
        }
    }
}


int main(void) {
    while (~scanf("%d%d%d", &n, &m, &k)) {
        ans = INF;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                scanf("%d", &a[i][j]);
            }
        }
        doit();
        gotit();
        printf("%d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(soj 3636 理想的正方形(二维单调队列))