BZOJ1047: [HAOI2007]理想的正方形(单调队列)

有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。

题解:以前居然不会做????

   这数据范围直接暴力就好了 先维护一下每行每n个数的最大最小值

   再像滑窗一样每n行的统计一下答案就行了

 

#include <bits/stdc++.h>
using namespace std;

int n, m, k;
int a[1005][1005];
int zd[1005]; int did[1005];
int zx[1005]; int xid[1005];
int mx[1005][1005];
int mi[1005][1005];

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++) scanf("%d", &a[i][j]);

    for(int i = 1; i <= n; i++)
    {
        int top1 = 1, tail1 = 0;
        int top2 = 1, tail2 = 0;
        int cnt = 0;
        for(int j = 1; j <= m; j++)
        {
            zd[++tail1] = a[i][j]; did[tail1] = j;
            while(top1 != tail1 && zd[tail1] >= zd[tail1 - 1]) tail1--, zd[tail1] = a[i][j], did[tail1] = j;
            while(j - did[top1] + 1 > k) top1++;

            zx[++tail2] = a[i][j]; xid[tail2] = j;
            while(top2 != tail2 && zx[tail2] <= zx[tail2 - 1]) tail2--, zx[tail2] = a[i][j], xid[tail2] = j;
            while(j - xid[top2] + 1 > k) top2++;
            if(j >= k) mx[i][++cnt] = zd[top1], mi[i][cnt] = zx[top2];
        }
    }

    int ans = 1e9;
    for(int i = 1; i <= m - k + 1; i++)
    {
        int top1 = 1, tail1 = 0;
        int top2 = 1, tail2 = 0;
        for(int j = 1; j <= n; j++)
        {
            zd[++tail1] = mx[j][i]; did[tail1] = j;
            while(top1 != tail1 && zd[tail1] >= zd[tail1 - 1]) tail1--, zd[tail1] = mx[j][i], did[tail1] = j;
            while(j - did[top1] + 1 > k) top1++;

            zx[++tail2] = mi[j][i]; xid[tail2] = j;
            while(top2 != tail2 && zx[tail2] <= zx[tail2 - 1]) tail2--, zx[tail2] = mi[j][i], xid[tail2] = j;
            while(j - xid[top2] + 1 > k) top2++;

            if(j >= k) ans = min(ans, zd[top1] - zx[top2]);
        }
    }
    printf("%d\n", ans);
    return 0;
}
View Code

 

posted @ 2018-10-22 20:47  lwqq3  阅读(135)  评论(0编辑  收藏  举报