BZOJ 1047: [HAOI2007]理想的正方形

来源:互联网 发布:centos 超时时间 编辑:程序博客网 时间:2024/05/29 17:36

题意:这里写链接内容

题意:
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

解题方法:
 将每个点开始向左n个点的最大最小值算出来,对行使用单调队列求最值。接着将每个点作为右下角的n∗n的矩阵的最大最小值求出来,使用刚才算出来的值,对列使用单调队列求最值
这样我们就算出来了每一个点对应的矩形的最大值减最小值!!

代码如下:

#include <bits/stdc++.h>using namespace std;const int N = 1010;int head, tail, que[N], maze[N][N], f[4][N][N];void getmin(int &x, int y){    if(y < x) x = y;}int main(){    int a, b, n;    while(scanf("%d%d%d", &a, &b, &n) != EOF){        for(int i = 1; i <= a; i++){            for(int j = 1; j <= b; j++){                scanf("%d", &maze[i][j]);            }        }        for(int i = 1; i <= a; i++){//对行做单调队列,维护这个点向左n个点的最大和最小            head = tail = 0;            for(int j = 1; j <= b; j++){//减                while(head < tail && j - que[head] >= n) ++head;                while(head < tail && maze[i][j] <= maze[i][que[tail - 1]]) --tail;                que[tail++] = j;                f[0][i][j]  = maze[i][que[head]];            }            head = tail = 0;            for(int j = 1; j <= b; j++){//增                while(head < tail && j - que[head] >= n) ++head;                while(head < tail && maze[i][j] >= maze[i][que[tail - 1]]) --tail;                que[tail++] = j;                f[1][i][j] = maze[i][que[head]];            }        }        for(int j = 1; j <= b; j++){ //对列做单调队列,相当于(i, j)点往上延伸n距离的最大值和最小值            head = tail = 0;            for(int i = 1; i <= a; i++){//减                while(head < tail && i - que[head] >= n) ++head;                while(head < tail && f[0][i][j] <= f[0][que[tail-1]][j]) --tail;                que[tail++] = i;                f[2][i][j] = f[0][que[head]][j];            }            head = tail = 0;            for(int i = 1; i <= a; i++){//增                while(head < tail && i - que[head] >= n) ++head;                while(head < tail && f[1][i][j] >= f[1][que[tail-1]][j]) --tail;                que[tail++] = i;                f[3][i][j] = f[1][que[head]][j];            }        }        int ans = 1000000000;        for(int i = n; i <= a; i++){            for(int j = n; j <= b; j++){                getmin(ans, f[3][i][j] - f[2][i][j]);            }        }        printf("%d\n", ans);    }    return 0;}
0 0
原创粉丝点击