~~~题面~~~

题解:

  因为数据范围不大,而且题目要求的是正方形,所以这道题有2种解法。

  1,st表。

    这种解法暴力好写好理解,但是较慢。我们设st[i][j][k]表示以(i, j)为左端点,向下/向右分别扩展$2^k$格的最大值,最小值同理,处理完后$n^2$枚举左端点取最优值即可。

    (此为早期代码,写丑了不要介意)

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 1010
#define ac 110
//#define getchar() *S ++
//char READ[1250000],*S = READ;
int n,a,b,ans = INT_MAX;
int st_max[AC][AC][], st_min[AC][AC][];
int k, q = ;
//二维ST表emmmm inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline int Max(int a, int b, int c, int d)
{
if(a > b && a > c && a > d) return a;
else if(b > c && b > d) return b;
else if(c > d) return c;
else return d;
} inline int Min(int a, int b, int c, int d)
{
if(a < b && a < c && a < d) return a;
else if(b < c && b < d) return b;
else if(c < d) return c;
else return d;
} void pre()
{
a = read(), b = read(), n = read();
for(R i = ; i <= a; i ++)
for(R j = ; j <= b; j ++)
st_max[i][j][] = st_min[i][j][] = read();
} void check()
{
for(R i = ; i <= a; i ++)
for(R j = ; j <= b; j ++)
{
printf("!!!(%d , %d)\nst_max:\n", i, j);
for(R l = ; l <= k; l ++)
printf("2^%d = %d\n", l, st_max[i][j][l]);
printf("\n");
printf("st_min:\n");
for(R l = ; l <= k; l ++)
printf("2^%d = %d\n", l, st_min[i][j][l]);
printf("\n\n");
}
} void build()
{
while(n > q) q <<= , ++ k;
-- k, q >>= ;
int pos=;
for(R l = ; l <= k; l ++)
{
for(R i = pos + ; i <= a; i ++)
{
for(R j = pos + ; j <= b; j ++)
{
st_max[i][j][l] = Max(st_max[i - pos][j][l - ], st_max[i][j - pos][l - ], st_max[i - pos][j - pos][l - ], st_max[i][j][l - ]);
st_min[i][j][l] = Min(st_min[i - pos][j][l - ], st_min[i][j - pos][l - ], st_min[i - pos][j - pos][l - ], st_min[i][j][l - ]);
}
}
pos <<= ;
}
} void work()
{
int maxn, minn;
for(R i = n; i <= a; i ++)
for(R j = n; j <= b; j ++)
{
maxn = Max(st_max[i][j][k], st_max[i - n + q][j - n + q][k], st_max[i - n + q][j][k], st_max[i][j - n + q][k]);
minn = Min(st_min[i][j][k], st_min[i - n + q][j - n + q][k], st_min[i - n + q][j][k], st_min[i][j - n + q][k]);
ans = min(ans, maxn - minn);
}
printf("%d\n", ans);
} int main()
{
// freopen("in.in", "r", stdin);
//fread(READ, 1, 1200000, stdin);
pre();
build();
//check();
work();
// fclose(stdin);
return ;
}

  2,单调队列。

    其实也好理解,,,但是感觉很多博客没有图所以意思讲的不是很清晰,这里就详细讲一下吧。

    类似于滑动窗口,如果没做过这题建议先理解这题的做法。

    可以看做此题就是滑动窗口的二维扩展版。那么我们已经有了在序列上获取指定区间大小的最大最小值的方法,要如何才能扩展到二维平面上呢?

    其实画个图就很好理解了。

    如果我们将每个红色区间的最大最小值都存在蓝色点上,那么只需要对蓝色点做一次滑动窗口,就可以获得指定大小的矩形最大最小值了。

    因为每个蓝色点已经代表了指定区间大小的行的最大最小值,所以再在这个基础上查询蓝点指定区间的最大最小值就相当于是在查询一个矩形了。

    

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 1100
#define LL long long int n, m, k, ans = INT_MAX;
int s[AC][AC], g[AC][AC], f[AC][AC]; struct node{
int x, id;
}; struct que{
node q[AC];int head, tail;
void init()
{
head = , tail = ;
} void add_max(int x, int id)
{
while(head <= tail && q[head].id <= id - k) ++ head;
while(head <= tail && q[tail].x <= x) -- tail;
q[++tail] = (node){x, id};
} void add_min(int x, int id)
{
while(head <= tail && q[head].id <= id - k) ++ head;
while(head <= tail && q[tail].x >= x) -- tail;
q[++tail] = (node){x, id};
} int top() {return q[head].x;}
}q1, q2; inline void upmin(int &a, int b)
{
if(b < a) a = b;
} inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} void pre()
{
n = read(), m = read(), k = read();
for(R i = ; i <= n; i ++)
for(R j = ; j <= m; j ++) s[i][j] = read();
} void build()//先对每一行求出来
{
for(R i = ; i <= n; i ++)//枚举行
{
q1.init(), q2.init();
for(R j = ; j <= m; j ++)//枚举列
{
q1.add_min(s[i][j], j), q2.add_max(s[i][j], j);
if(j >= k) f[i][j] = q1.top(), g[i][j] = q2.top();
}
}
} void work()//再求整体的
{
for(R i = k; i <= m; i ++)//先枚举列,再枚举行
{
q1.init(), q2.init();
for(R j = ; j <= n; j ++)
{
q1.add_min(f[j][i], j), q2.add_max(g[j][i], j);
if(j >= k) upmin(ans, q2.top() - q1.top());
}
}
printf("%d\n", ans);
} int main()
{
// freopen("in.in", "r", stdin);
pre();
build();
work();
// fclose(stdin);
return ;
}

[HAOI2007]理想的正方形 st表 || 单调队列的更多相关文章

  1. P2216 [HAOI2007]理想的正方形(dp+单调队列优化)

    题目链接:传送门 题目: 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表 ...

  2. [BZOJ1047][HAOI2007]理想的正方形 二维单调队列

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1047 我们对每矩阵的一列维护一个大小为$n$的单调队列,队中元素为矩阵中元素.然后扫描每一 ...

  3. bzoj1047 [HAOI2007]理想的正方形——二维单调队列

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1047 就是先对行做一遍单调队列,再对那个结果按列做一遍单调队列即可. 代码如下: #incl ...

  4. [Bzoj1047][HAOI2007]理想的正方形(ST表)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1047 题目虽然有一个n的限制,但求二维区间最值首先想到的还是RMQ,但是如果按照往常RM ...

  5. Codeforces Round #278 (Div. 1) B - Strip dp+st表+单调队列

    B - Strip 思路:简单dp,用st表+单调队列维护一下. #include<bits/stdc++.h> #define LL long long #define fi first ...

  6. [luogu2216 HAOI2007] 理想的正方形 (2dST表 or 单调队列)

    题目描述 有一个ab的整数组成的矩阵,现请你从中找出一个nn的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至第a ...

  7. [Bzoj4540][Hnoi2016] 序列(莫队 + ST表 + 单调队列)

    4540: [Hnoi2016]序列 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1567  Solved: 718[Submit][Status] ...

  8. P2216 [HAOI2007]理想的正方形

    题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至 ...

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

    1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2857  Solved: 1560[Submit][St ...

随机推荐

  1. 前端javaScript经典面试题

    1.alert(1&&2),alert(1||0) alert(1&&2)的结果是2 只要“&&”前面是false,无论“&&”后面是t ...

  2. 11个简单实用技巧--Java性能调优

    多数开发人员认为性能优化是个比较复杂的问题,需要大量的经验和知识.是的,这并不没有错.诚然,优化应用程序以获得最好的性能并不是一件容易的事情,但这并不意味着你在没有获得这些经验和知识之前就不能做任何事 ...

  3. python装饰器+递归+冒泡排序

    冒泡排序 li = [33, 2, 10, 1,23,23523,5123,4123,1,2,0] for k in range(1,len(li)): for i in range(len(li) ...

  4. pwa学习笔记--简介

    1. 介绍 Progressive Web App , (渐进式增强 WEB 应用) 简称 PWA ,是提升WebApp的体验的一种新方法,能给用户原生应用的体验. PWA 本质上是 Web App ...

  5. Delphi中Templates代码模板添加注意事项

    今天用Delphi中的代码模板添加一段代码,结果就是有问题,多次测试后,发现是编码需要注意. <?xml version="1.0" encoding="GB231 ...

  6. CSS3不一样的下拉选择框

    本例中包含两个下拉选择框的动画示例,本例中并未使用select标签.本例中第一个案例也可用于标题.导航栏等位置. 案例一: html布局 <div class="content&quo ...

  7. ORB-SLAM 代码笔记(四)tracking代码结构

    首先要清楚ORB-SLAM视觉跟踪的原理,然后对tracking.cc中的函数逐个讲解 代码的前面部分是从配置文件中读取校准好的相机参数(内参和畸变参数,以及双目的深度测量设定),并且加载ORB特征点 ...

  8. Hystrix入门指南

    Introduction 1.Where does the name come from? hystrix对应的中文名字是“豪猪”,豪猪周身长满了刺,能保护自己不受天敌的伤害,代表了一种防御机制,这与 ...

  9. Linux下创建pycharm的快捷方式

    第一步:创建桌面快捷方式文件Pycharm.desktop,并打开 sudo gedit /usr/share/applications/Pycharm.desktop 第二步:在打开的文件Pycha ...

  10. 在Kotlin编写RecyclerView适配器(KAD 16)

    作者:Antonio Leiva 时间:Mar 14, 2017 原文链接:https://antonioleiva.com/recyclerview-adapter-kotlin/ 通过创建Recy ...