BZOJ 1047 [HAOI2007]理想的正方形

【看了题解才会做

这是一个典型的二维滑动窗口问题~

二维滑动窗口问题的处理方法可以类比一维滑动窗口的处理方法

首先将矩阵分解成B个列,对这B个列分别用单调队列维护一个长度为N的一维滑动窗口。记录colmax[i][j]为第j列第i行的元素(即第j个列的第i个元素)到第j列第i-N+1的元素(即第j个列的第i-N+1个元素)的最大值。这个用单调队列随便维护一下就好啦~

然后将矩阵分解成A个行,对这A个行再分别用单调队列维护一个长度为N的一维滑动窗口。记录rowmax[i][j]为colmax[i][j]~colmax[i][j-N+1]的最大值。显然地,此时rowmax[i][j]就是第i行第j列的元素到第i-N+1行第j-N+1列的元素(二维的)的最大值。

然后再做一遍最小值的。最后扫描一遍就可以啦~

  1 #include <deque>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5
  6 using namespace std;
  7
  8 void Get_Val(int &Ret)
  9 {
 10     Ret = 0;
 11     char ch;
 12     while ((ch = getchar()), (ch > ‘9‘ || ch < ‘0‘))
 13         ;
 14     do
 15     {
 16         (Ret *= 10) += ch - ‘0‘;
 17     }
 18     while ((ch = getchar()), (ch >= ‘0‘ && ch <= ‘9‘));
 19 }
 20
 21 const size_t Max_AB(1050);
 22
 23 int A, B;
 24 int N;
 25 int Value[Max_AB][Max_AB];
 26
 27 int colmax[Max_AB][Max_AB], rowmax[Max_AB][Max_AB];
 28 int colmin[Max_AB][Max_AB], rowmin[Max_AB][Max_AB];
 29
 30 void init()
 31 {
 32     Get_Val(A), Get_Val(B), Get_Val(N);
 33     for (int i = 1;i <= A;++i)
 34         for (int j = 1;j <= B;++j)
 35             Get_Val(Value[i][j]);
 36 }
 37
 38 struct node
 39 {
 40     node(const int &a = 0, const int &b = 0) : Number(a), Value(b) {}
 41     int Number;
 42     int Value;
 43 };
 44
 45 void Col_Max(int col[][Max_AB])
 46 {
 47     deque<node> Q;
 48     for (int j = 1;j <= B;++j)
 49     {
 50         Q.clear();
 51         for (int i = 1;i <= A;++i)
 52         {
 53             while (!Q.empty() && Q.back().Value < Value[i][j])
 54                 Q.pop_back();
 55             Q.push_back(node(i, Value[i][j]));
 56             if (Q.front().Number < i - N + 1)
 57                 Q.pop_front();
 58             col[i][j] = Q.front().Value;
 59         }
 60     }
 61 }
 62
 63 void Row_Max(int col[][Max_AB], int row[][Max_AB])
 64 {
 65     deque<node> Q;
 66     for (int i = 1;i <= A;++i)
 67     {
 68         Q.clear();
 69         for (int j = 1;j <= B;++j)
 70         {
 71             while (!Q.empty() && Q.back().Value < col[i][j])
 72                 Q.pop_back();
 73             Q.push_back(node(j, col[i][j]));
 74             if (Q.front().Number < j - N + 1)
 75                 Q.pop_front();
 76             row[i][j] = Q.front().Value;
 77         }
 78     }
 79 }
 80
 81 void work()
 82 {
 83     Col_Max(colmax);
 84     Row_Max(colmax, rowmax);
 85     for (int i = 1;i <= A;++i)
 86         for (int j = 1;j <= B;++j)
 87             Value[i][j] = -Value[i][j];
 88     Col_Max(colmin);
 89     Row_Max(colmin, rowmin);
 90 }
 91
 92 void Get_Ans()
 93 {
 94     int Ans(0X7F7F7F7F);
 95     for (int i = N;i <= A;++i)
 96         for (int j = N;j <= B;++j)
 97             Ans = min(Ans, rowmax[i][j] + rowmin[i][j]);
 98     printf("%d", Ans);
 99 }
100
101 int main()
102 {
103     init();
104     work();
105     Get_Ans();
106     return 0;
107 }

BZOJ 1047

时间: 2024-10-25 19:25:54

BZOJ 1047 [HAOI2007]理想的正方形的相关文章

BZOJ 1047 HAOI2007 理想的正方形 单调队列

题目大意:给定一个a*b的矩阵,求一个n*n的子矩阵,使矩阵中的最大值与最小值之差最小 对于每行维护一个单调递减的队列.再弄一个竖着的队列.维护n个格子之内的最大值就可以 两遍统计出最大值和最小值 然后得到ans就可以 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1010 using namespace std; struct abcd

bzoj 1047: [HAOI2007]理想的正方形【单调队列】

没有复杂结构甚至不长但是写起来就很想死的代码类型 原理非常简单,就是用先用单调队列处理出mn1[i][j]表示i行的j到j+k-1列的最小值,mx1[i][j]表示i行的j到j+k-1列的最大值 然后就变成求单列最大最小值,用上面同样的方法处理出对于列的mn2mx2即可 #include<iostream> #include<cstdio> using namespace std; const int N=1005; int n,m,k,a[N][N],mn1[N][N],mx1[

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

1047: [HAOI2007]理想的正方形——二维单调队列

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 对每一行维护一个单调队列,保存在lmin[][],lmax[][] 然后对每一列维护一个单调队列,最后n*n枚举 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define clr(a,b) memset(a,b,sizeof(a)) cons

1047: [HAOI2007]理想的正方形

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4075  Solved: 2277[Submit][Status][Discuss] Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.100%的数据2<=a,b<=

【BZOJ 1047】 [HAOI2007]理想的正方形

1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1685  Solved: 891 [Submit][Status] Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.

[BZOJ1047][HAOI2007]理想的正方形

1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 3481  Solved: 1917 [Submit][Status][Discuss] Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值 的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每 行相邻

RAM——[HAOI2007]理想的正方形

题目:[HAOI2007]理想的正方形 描述: [问题描述] 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. [输入]: 第一行为3个整数,分别表示a,b,n的值 第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔. [输出]: 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. [输入样例] 5 4 2 1 2 5 6 0 17 16 0 16 17

HAOI2007 理想的正方形 单调队列

单调队列 by   GeneralLiu 滑动窗口是比较裸的单调队列 理想的正方形   就拔高了一个层次(多了一维) 有一个a*b的整数组成的矩阵 现请你从中找出一个n*n的正方形区域 使得该区域所有数中的最大值和最小值的差最小 只写MAX了,MIN一个道理,懒 不写了 先横着跑单调队列 维护许多长度为 n 的 横着的MAX 存在数组 map1[][] 中 再对数组 map1[][] 竖着跑单调队列 就维护了 许多 n*n 的 矩阵的MAX MIN同理 在竖着跑单调队列时 顺便MAX 与 MIN