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

1047: [HAOI2007]理想的正方形

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4184  Solved: 2361
[Submit][Status][Discuss]

Description

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

Input

  第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000

Output

  仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。

Sample Input

5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2

Sample Output

1
题解:

  在各行通过单调队列维护第i行中以j为结尾的长度为n的区间的最大值maxn和最小值minn

  然后再在各列跑一边单调队列,求出所有n×n正方形区域的最大值和最小值之差

/**************************************************************
    Problem: 1047
    User: mizersy
    Language: C++
    Result: Accepted
    Time:1940 ms
    Memory:13144 kb
****************************************************************/
 
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
struct Node{
    int w,p;
};
Node high[N],low[N];
int head1,head2,tail1,tail2;
int maxn[N][N],minn[N][N];
int a[N][N];
int n,m,k;
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for (int i = 1;i <= n;++i){
        head1 = head2 = tail1 = tail2 = 0;
        for (int j = 1;j <= m;++j){
            scanf("%d",&a[i][j]);
            while(head1 < tail1 && high[tail1-1].w < a[i][j]) tail1--;
            while(head1 < tail1 && j - high[head1].p >= k) head1++;
            high[tail1++] = Node{a[i][j],j};
            if (j >= k) maxn[i][j] = high[head1].w;
            while(head2 < tail2 && low[tail2-1].w > a[i][j]) tail2--;
            while(head2 < tail2 && j - low[head2].p >= k)head2++;
            low[tail2++] = Node{a[i][j],j};
            if (j >= k) minn[i][j] = low[head2].w;
        }
    }
    int ans = 1e9+7;
    for (int j = k;j <= m;++j){
        head1 = head2 = tail1 = tail2 = 0;
        for (int i = 1;i <= n;++i){
            while(head1 < tail1 && high[tail1-1].w < maxn[i][j]) tail1--;
            while(head1 < tail1 && i - high[head1].p >= k) head1++;
            high[tail1++] = Node{maxn[i][j],i};
            while(head2 < tail2 && low[tail2-1].w > minn[i][j]) tail2--;
            while(head2 < tail2 && i - low[head2].p >= k) head2++;
            low[tail2++] = Node{minn[i][j],i};
            if (j >= k && i >= k){
                ans = min(ans,high[head1].w - low[head2].w);
            }
        }
    }
    printf("%d\n",ans);
}

 

posted @ 2018-08-28 20:10  mizersy  阅读(112)  评论(0编辑  收藏  举报