[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 ...
随机推荐
- Linux Terminal fortune
Linux下,我们能够使用apt-get安装fortune,这是一个比較有趣的功能 在输入fortune之后,Terminal会输出一句名言.诗句,或一些有趣的话: 默认情况下.fortune仅仅会显 ...
- MyBatis中sqlSession操作数据库,不报错但无法实现数据修改(增、改、删)
public void addCustomerTest() throws Exception { SqlSession sqlSession = MyBatisUtils.getSession(); ...
- Window上python 开发--1.搭建开发环境
事实上在开发python最好在ubuntu环境下,简单也便于扩展各个package.可是我的linux的电脑临时不在身边.还的我老婆的电脑win7没办法啊. 因为python的跨平台性.在window ...
- luogu1541 乌龟棋 动态规划
题目大意 一行格子,每个格子里有数字.一些卡片,卡片上有1.2.3.4这几种数字.一开始你在格子1,随后每次选一个卡片,你可以前进卡片上的数字个格子,得到格子上的分数,然后讲该卡片丢弃.求取卡片的顺序 ...
- [ASPX] 模版引擎XTemplate与代码生成器XCoder(源码)
模版引擎XTemplate是一个仿T4设计的引擎,功能上基本与T4一致(模版语法上完全兼容T4,模版头指令部分兼容). 自己设计模版引擎,就是为了代码生成器.网站模版.邮件模版等多种场合,也就是要能拿 ...
- [JXOI 2018] 守卫 解题报告 (DP)
interlinkage: https://www.luogu.org/problemnew/show/P4563 description: solution: 注意到对于范围$[l,r]$,$r$这 ...
- office2016专业版激活码
office2016专业版激活密钥 Office 2016 Pro Plus Retail 版激活密钥:office2016专业版激活码 [Key]:3XJTG-YNBMY-TBH9M-CWB2Y-Y ...
- [XJOI]noip44 T3还有这种操作
还有这种操作 ttt 最近在学习二进制, 他想知道小于等于N的数中有多少个数的二进制表示中有偶数个1. 但是他想了想觉得不够dark,于是他增加了若干次操作,每次操作会将一个区间内的0变1 , 1变0 ...
- 关于一些UI的插件(杂)
1.时间插件 //日期框 $('.date-picker').datepicker(); 2.checkbox 保存checkbox的值 // 组装选择的标签 var check = $(" ...
- C# WinForm的练习
今天写了一个WinForm的练习,将源代码贴出来和大家一起学习学习. 首先:按照下图将一个button控件.三个RadioButton控件.三个CheckBox控件.一个Label控件和一个Track ...