[luogu2216 HAOI2007] 理想的正方形 (2dST表 or 单调队列)
题目描述
有一个ab的整数组成的矩阵,现请你从中找出一个nn的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入输出格式
输入格式:
第一行为3个整数,分别表示a,b,n的值
第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出格式:
仅一个整数,为ab矩阵中所有“nn正方形区域中的最大整数和最小整数的差值”的最小值。
输入输出样例
输入样例#1:
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
输出样例#1:
1
说明
问题规模
(1)矩阵中的所有数都不超过1,000,000,000
(2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10
(3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100
题解
反正我一看到题就想着用ST表。。
不过后来发现还有一种更优秀的做法,那便是利用单调队列,求出一个满足一维上的最值数组
之后这个最值数组上再次利用单调队列求出二维的最值数组,便可以更优秀的时间复杂度过掉这道题(而且代码也不长)
code:(2dST表) 很好写
//By Menteur_Hxy
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
int rd() {
int x=0,f=1; char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-f; c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
return x*f;
}
const int INF=0x7fffffff;
const int MAX=1050;
int a,b,n,m;
int ma[MAX][MAX][12],mi[MAX][MAX][12];
inline int min(int a,int b) {
if(a<b) return a;
return b;
}
inline int max(int a,int b) {
if(a>b) return a;
return b;
}
void init() {
F(k,1,11) F(i,1,a-(1<<k)+1) F(j,1,b-(1<<k)+1)
mi[i][j][k]=min(min(mi[i][j][k-1],mi[i+(1<<(k-1))][j+(1<<(k-1))][k-1]),
min(mi[i+(1<<(k-1))][j][k-1],mi[i][j+(1<<(k-1))][k-1])),
ma[i][j][k]=max(max(ma[i][j][k-1],ma[i+(1<<(k-1))][j+(1<<(k-1))][k-1]),
max(ma[i+(1<<(k-1))][j][k-1],ma[i][j+(1<<(k-1))][k-1]));
}
inline int query(int i,int j) {
int maxn=-INF,minn=INF;
minn=min(min(mi[i][j][m],mi[i+n-(1<<m)][j+n-(1<<m)][m]),
min(mi[i+n-(1<<m)][j][m],mi[i][j+n-(1<<m)][m]));
maxn=max(max(ma[i][j][m],ma[i+n-(1<<m)][j+n-(1<<m)][m]),
max(ma[i+n-(1<<m)][j][m],ma[i][j+n-(1<<m)][m]));
return maxn-minn;
}
int main() {
a=rd(),b=rd(),n=rd();
F(i,1,a) F(j,1,b) ma[i][j][0]=mi[i][j][0]=rd();
init(); m=log(n)/log(2); int ans=INF;
F(i,1,a-n+1) F(j,1,b-n+1) ans=min(ans,query(i,j));
printf("%d",ans);
return 0;
}
code:(单调队列)
//By Menteur_Hxy
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
int rd() {
int x=0,f=1; char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-f; c=getchar();}
while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
return x*f;
}
const int N=1050,INF=0x7fffffff;
int n,m,k,ans=INF,h,H,T,t;
int da[N][N],X[N][N],x[N][N],Y[N][N],y[N][N],Q[N<<1],q[N<<1];
int main() {
n=rd(),m=rd(),k=rd();
F(i,1,n) F(j,1,m) da[i][j]=rd();
F(i,1,n) { H=T=h=t=Q[1]=q[1]=1;
F(j,2,m) {
while(T>=H and da[i][j]>=da[i][Q[T]]) T--;
while(t>=h and da[i][j]<=da[i][q[t]]) t--;
t++,T++; q[t]=Q[T]=j;
while(j-Q[H]>=k) H++;
while(j-q[h]>=k) h++;
if(j>=k) X[i][j-k+1]=da[i][Q[H]],x[i][j-k+1]=da[i][q[h]];
}
}
F(i,1,m-k+1) { H=T=t=h=Q[1]=q[1]=1;
F(j,2,n) {
while(T>=H and X[j][i]>=X[Q[T]][i]) T--;
while(t>=h and x[j][i]<=x[q[t]][i]) t--;
t++,T++; q[t]=Q[T]=j;
while(j-Q[H]>=k) H++;
while(j-q[h]>=k) h++;
if(j>=k) Y[j-k+1][i]=X[Q[H]][i],y[j-k+1][i]=x[q[h]][i],
ans=min(ans,Y[j-k+1][i]-y[j-k+1][i]);
}
}
return printf("%d",ans),0;
}
[luogu2216 HAOI2007] 理想的正方形 (2dST表 or 单调队列)的更多相关文章
- [bzoj1047][HAOI2007]理想的正方形_动态规划_单调队列
理想的正方形 bzoj-1047 HAOI-2007 题目大意:有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 注释:$2\le a, ...
- [luoguP2216] [HAOI2007]理想的正方形(二维单调队列)
传送门 1.先弄个单调队列求出每一行的区间为n的最大值最小值. 2.然后再搞个单调队列求1所求出的结果的区间为n的最大值最小值 3.最后扫一遍就行 懒得画图,自己体会吧. ——代码 #include ...
- [HAOI2007]理想的正方形 st表 || 单调队列
~~~题面~~~ 题解: 因为数据范围不大,而且题目要求的是正方形,所以这道题有2种解法. 1,st表. 这种解法暴力好写好理解,但是较慢.我们设st[i][j][k]表示以(i, j)为左端点,向下 ...
- luogu2216 [HAOI2007]理想的正方形
先对于每一行中长度为 n 的列用单调队列搞出它们的最小/大值,再将这些长度为 n 的列想象成点再对行跑一遍 #include <iostream> #include <cstring ...
- [Bzoj1047][HAOI2007]理想的正方形(ST表)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1047 题目虽然有一个n的限制,但求二维区间最值首先想到的还是RMQ,但是如果按照往常RM ...
- 【BZOJ1047】[HAOI2007]理想的正方形 (倍增ST表)
[HAOI2007]理想的正方形 题目描述 有一个\(a*b\)的整数组成的矩阵,现请你从中找出一个\(n*n\)的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: ...
- 【BZOJ1047】[HAOI2007]理想的正方形
[BZOJ1047][HAOI2007]理想的正方形 题面 bzoj 洛谷 题解 二维\(st\)表,代码是以前的 #include<iostream> #include<cstdi ...
- [Luogu 2216] [HAOI2007]理想的正方形
[Luogu 2216] [HAOI2007]理想的正方形 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输 ...
- BZOJ1047: [HAOI2007]理想的正方形 [单调队列]
1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2857 Solved: 1560[Submit][St ...
随机推荐
- Eclipse没有Run On Server的问题解决
1.[项目]->[右击]->[Properties]->[Project Facets]->[Modify Project],选择[Java]和[Dynamic Web Mod ...
- [DLX精确覆盖] hdu 3663 Power Stations
题意: 给你n.m.d,代表有n个城市.m条城市之间的关系,每一个城市要在日后d天内都有电. 对于每一个城市,都有一个发电站,每一个发电站能够在[a,b]的每一个连续子区间内发电. x城市发电了.他相 ...
- Linux内核中网络数据包的接收-第二部分 select/poll/epoll
和前面文章的第一部分一样,这些文字是为了帮别人或者自己理清思路的.而不是所谓的源代码分析.想分析源代码的,还是直接debug源代码最好,看不论什么文档以及书都是下策. 因此这类帮人理清思路的文章尽可能 ...
- Python面向切面编程-语法层面和functools模块
1,Python语法层面对面向切面编程的支持(方法名装饰后改变为log) __author__ = 'Administrator' import time def log(func): def wra ...
- Floyed理解
Floyed理解 Floyd算法的本质是动态规划,其转移方程为:f(k,i,j) = min( f(k-1,i,j), f(k-1,i,k)+f(k-1,k,j) ). f(k-1,i,j)表示经过前 ...
- 对象设计解耦的方法IOC和DI
耦合关系不仅会出现在对象与对象之间,也会出现在软件系统的各模块之间,以及软件系统和硬件系统之间.如何降低系统之间.模块之间和对象之间的耦合度,是软件工程永远追求的目标之一.为了解决对象之间的耦合度过高 ...
- springboot整合ActiveMQ 2(主备模式,负载均衡)
基本使用,https://www.tapme.top/blog/detail/2018-09-05-10-38 主备模式,https://www.tapme.top/blog/detail/2018- ...
- shell 杂集
1.shell 相等比较注意 -eq 数字相等的比较 == 字符串相等的比较 2.== 和 = 的区别 == 可用于判断变量是否相等,= 除了可用于判断变量是否相等外,还可以表示赋值. = 与 == ...
- Codeforces Round #453
Visiting a Friend Solution Coloring a Tree 自顶向下 Solution Hashing Trees 连续2层节点数都超过1时能异构 Solution GCD ...
- 给WordPress的TinyMCE Advanced编辑器加上中文字体
为TinyMCE编辑器增加中文字体并不复杂,只需要将将如下代码加到当前主题的functions.php文件中最后一个?>的前面即可: 不要忘记保存,然后更新一遍浏览器即可 //为TinyMCE编 ...