[Luogu 2216] [HAOI2007]理想的正方形
[Luogu 2216] [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 2 1
2 10 2 1
1 2 2 2
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
抱着刷DP的心理,打开了这道题,但好像并不会DP qaq,这里介绍一种二维st的方法
题解:
因为本蒟蒻是刚复习了一下st表做RMQ,所以顺手继续做了
因为我们发现n是不变的,所以st表的时候可以只开三维f[a][b][log n]
然后就可以根据一维st表一样的预处理方式,只是一个状态需要从四个状态转移过来
因为一个正方形肯定是可以分成四个部分的,可能包含重叠.
所以就是这样,然后最后查询的时候也是分成四个部分
于是就结束了...
#include<bits/stdc++.h>
using namespace std;
const int N=;
int a,b,n,lg,ans=1e9;
int mp[N][N],f[N][N][],g[N][N][];
int Min(int a,int b,int c,int d){
return min(a,min(b,min(c,d)));
}
int Max(int a,int b,int c,int d){
return max(a,max(b,max(c,d)));
}
int ask1(int x,int y){
int dx=x+n-,dy=y+n-;
return Max(g[x][y][lg],g[x][dy-(<<lg)+][lg],g[dx-(<<lg)+][y][lg],g[dx-(<<lg)+][dy-(<<lg)+][lg]);
}
int ask2(int x,int y){
int dx=x+n-,dy=y+n-;
return Min(f[x][y][lg],f[x][dy-(<<lg)+][lg],f[dx-(<<lg)+][y][lg],f[dx-(<<lg)+][dy-(<<lg)+][lg]);
}
int main(){
scanf("%d%d%d",&a,&b,&n); memset(f,0x3f3f,sizeof(f)); memset(g,,sizeof(g));
for (int i=;i<=a;++i)
for (int j=;j<=b;++j)
scanf("%d",&mp[i][j]),f[i][j][]=g[i][j][]=mp[i][j];
for (int k=;(<<k)<=n;++k)
for (int i=;i+(<<k)-<=a;++i)
for (int j=;j+(<<k)-<=b;++j){
f[i][j][k]=Min(f[i][j][k-],f[i][j+(<<(k-))][k-],f[i+(<<(k-))][j][k-],f[i+(<<(k-))][j+(<<k-)][k-]);
g[i][j][k]=Max(g[i][j][k-],g[i][j+(<<(k-))][k-],g[i+(<<(k-))][j][k-],g[i+(<<(k-))][j+(<<k-)][k-]);
}
lg=(int)(log(n)/log(2.0));
for (int i=;i<=a-n+;++i)
for (int j=;j<=b-n+;++j)
ans=min(ans,ask1(i,j)-ask2(i,j));
printf("%d",ans);
}
然而事实上,我觉得单调队列的做法也是非常好的,于是借鉴了别人的题解,此下贴出
对于每一行,我们维护定长区间内的最大值和最小值,maxv[i][j]表示第i行第j列,从j-k+1~j这些数的最大值,minv[i][j]同理。这里的k是题目中的n,也就是正方形的长。然后我们已经知道每一行定长区间内的最值,对于每一列,我们也同样维护这一列定长区间的最值,就能得到一个“定正方形”内的最值。
至于定长区间的最值怎么求,那就是用到我们的单调队列了,这道题其实是个模板。这里我是开两个双端队列,maxq和minq,分别维护。(当然开一个也可以,那样代码就比较长了)
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std; const int N = ;
const int INF = 1e9;
int n, m, k, a[N][N], maxv[N][N], minv[N][N]; int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i=; i<=n; i++)
for (int j=; j<=m; j++) scanf("%d", &a[i][j]);
//以下对于每一行用单调队列求出maxv[i][j]和minv[i][j]
for (int i=; i<=n; i++){
deque<int> maxq, minq;
maxv[i][] = ;
minv[i][] = INF;
for (int j=; j<=m; j++){
while (!maxq.empty() && maxq.front() < j-k+) maxq.pop_front(); //如果范围超过k就弹出队列
while (!maxq.empty() && a[i][maxq.back()] <= a[i][j]) maxq.pop_back(); //维护单调递减的队列使得队首为最大值
maxq.push_back(j);
maxv[i][j] = a[i][maxq.front()];
while (!minq.empty() && minq.front() < j-k+) minq.pop_front();
while (!minq.empty() && a[i][minq.back()] >= a[i][j]) minq.pop_back(); //维护单调递增的队列使得队首为最小值
minq.push_back(j);
minv[i][j] = a[i][minq.front()];
}
}
//以下对于每一列用单调队列求出“定正方形”内最值,并直接计算答案
int ans = INF;
for (int j=k; j<=m; j++){ //注意枚举范围从k开始
deque<int> maxq, minq;
int MaxV = ;
int MinV = INF;
for (int i=; i<=n; i++){
//单调队列用法同上
while (!maxq.empty() && maxq.front() < i-k+) maxq.pop_front();
while (!maxq.empty() && maxv[maxq.back()][j] <= maxv[i][j]) maxq.pop_back();
maxq.push_back(i);
MaxV = maxv[maxq.front()][j];
while (!minq.empty() && minq.front() < i-k+) minq.pop_front();
while (!minq.empty() && minv[minq.back()][j] >= minv[i][j]) minq.pop_back();
minq.push_back(i);
MinV = minv[minq.front()][j];
if (i >= k) ans = min(ans, MaxV - MinV); //注意i >= k时才能更新答案
}
}
printf("%d\n", ans);
return ;
}
[Luogu 2216] [HAOI2007]理想的正方形的更多相关文章
- Luogu 2216[HAOI2007]理想的正方形 - 单调队列
Solution 二维单调队列, 这个数组套起来看得我眼瞎... Code #include<cstdio> #include<algorithm> #include<c ...
- Luogu 2216 [HAOI2007]理想的正方形 (单调队列优化)
题意: 给出一个 N×M 的矩阵,以及一个数值 K ,求在给定的矩阵中取出一个 K×K 的矩阵其中最大值减去最小值的最小值. 细节: 没有细节来发暴力走天下,20分也是分啊~~~ QAQ. 分析: 感 ...
- BZOJ1047或洛谷2216 [HAOI2007]理想的正方形
BZOJ原题链接 洛谷原题链接 显然可以用数据结构或\(ST\)表或单调队列来维护最值. 这里采用单调队列来维护. 先用单调队列维护每一行的最大值和最小值,区间长为正方形长度. 再用单调队列维护之前维 ...
- 洛谷 2216 [HAOI2007]理想的正方形
题目戳这里 一句话题意 给你一个a×b的矩形,求一个n×n的子矩阵,矩阵里面的最大值和最小值之差最小. Solution 这个题目许多大佬都是单调队列,但是我不是很会,只好用了比较傻逼的方法: 首先我 ...
- BZOJ1047: [HAOI2007]理想的正方形 [单调队列]
1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2857 Solved: 1560[Submit][St ...
- HAOI2007 理想的正方形
1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1402 Solved: 738[Submit][Sta ...
- RAM——[HAOI2007]理想的正方形
题目:[HAOI2007]理想的正方形 描述: [问题描述] 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. [输入]: 第一行为3个 ...
- bzoj 1047 : [HAOI2007]理想的正方形 单调队列dp
题目链接 1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2369 Solved: 1266[Submi ...
- BZOJ 1047: [HAOI2007]理想的正方形( 单调队列 )
单调队列..先对每一行扫一次维护以每个点(x, y)为结尾的长度为n的最大最小值.然后再对每一列扫一次, 在之前的基础上维护(x, y)为结尾的长度为n的最大最小值. 时间复杂度O(ab) (话说还是 ...
随机推荐
- -bash:whois:command not found
在centOS 下,如果出现-bash:whois:command not found的问题, 则yum install 安装whois软件 yum install -y jwhois 包名是jwho ...
- 安装 jdk 和 IDE软件
1.jdk的安装 通过官方网站获取JDK http://www.oracle.com 针对不同操作系统,下载不同的JDK版本 识别计算机的操作系统 下载完后进行安装,傻瓜式安装,下一步下一步即可.用j ...
- matplotlib命令与格式:标题(title),标注(annotate),文字说明(text)
1.title设置图像标题 (1)title常用参数 fontsize设置字体大小,默认12,可选参数 ['xx-small', 'x-small', 'small', 'medium', 'la ...
- enote笔记语言(4)
what:我想知道某个“关键词(keyword)”(即,词语,可以是概念|专业术语|.......)的定义. why:我想知道事物发生的原因:我会不会犯“归因错误”?是“单因素”的还是“多因素”的原因 ...
- [Luogu] P3413 萌数
题目背景 本题由世界上最蒟蒻最辣鸡最撒比的SOL提供. 寂月城网站是完美信息教室的官网.地址:已和谐 . 题目描述 辣鸡蒟蒻SOL是一个傻逼,他居然觉得数很萌! 好在在他眼里,并不是所有数都是萌的.只 ...
- (39.4) Spring Boot Shiro权限管理【从零开始学Spring Boot】
在读此文章之前您还可能需要先了解: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...
- Tomcat关闭后,重新启动,session中保存的对象为什么还存在解决方法
Tomcat关闭后,重新启动,session中保存的对象为什么还存在各们朋友大家好: 当我关闭Tomcat,重新启动后,session中保存的对象还依然存在,仍然可以使用,不知这是什么 ...
- ESXi License过期解决办法
http://blog.sina.com.cn/s/blog_538439270101pqls.html
- nyoj_114_某种序列_201403161700
某种序列 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 数列A满足An = An-1 + An-2 + An-3, n >= 3 编写程序,给定A0, A1 ...
- [bzoj1010][HNOI2008]玩具装箱toy_斜率优化dp
玩具装箱toy bzoj-1010 HNOI-2008 题目大意:P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一 ...