[bzoj1047][HAOI2007]理想的正方形_动态规划_单调队列
理想的正方形 bzoj-1047 HAOI-2007
题目大意:有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
注释:$2\le a,b,n\le 10^3$,$n\le min(a,b)$。
想法:我的思路简直要死。通常的,我们优化暴力来完成对题目的求解。首先,想暴力。漂亮的暴力没想到,倒是想到一个a*b*n*n的,就是枚举每一个点,如果这个点可以作为n*n正方形的左上角,我就暴力枚举这个正方形的所有点。时间复杂度:O((a-n)*(b-n)*n*n)O(挖坑代填过不去)。想怎么优化:首先我们想,暴力的时候是连续的将n*n个数取最大值,我们可以怎么优化?我们可以对于每一行来讲维护一个窗口长度为n的单调队列来求出以每一个点结尾的前n个数的最值。然后我.. ....tm自以为是正解然后开始敲。自然T了之后还不知道怎么肥四,以为bz评测机又jb炸了。仔细分析了一下发现不太对。总的时间复杂度是a*b*n的,满的话是$10^9$的,不T才怪... ...想想再优化优化就好了嘛。对于求出来的矩阵,maxn[i][j]表示原矩阵以(i,j)为起点前n个数的最值。我们可以对maxn矩阵再维护一个窗口长度为n的单调队列,这样的话查询就是O(1)的了qwq.
最后,附上丑陋的代码... ...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 2000000000
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int a,b,n;
int v[1005][1005],mx[1005][1005],mn[1005][1005],t1[1005],t2[1005];
int val[1005],pos[1005];
void pre()
{
int l,r;
for(int i=1;i<=a;i++)
{
l=1,r=1;
for(int j=1;j<=b;j++)
{
while(l<r&&val[r-1]<=v[i][j])r--;
val[r]=v[i][j];pos[r]=j;r++;
if(pos[l]==j-n)l++;
if(j>=n)mx[i][j]=val[l];
}
l=1,r=1;
for(int j=1;j<=b;j++)
{
while(l<r&&val[r-1]>=v[i][j])r--;
val[r]=v[i][j];pos[r]=j;r++;
if(pos[l]==j-n)l++;
if(j>=n)mn[i][j]=val[l];
}
}
}
void solve()
{
int ans=inf;
int l,r;
for(int i=n;i<=b;i++)
{
l=1,r=1;
for(int j=1;j<=a;j++)
{
while(l<r&&val[r-1]>=mn[j][i])r--;
val[r]=mn[j][i];pos[r]=j;r++;
if(pos[l]==j-n)l++;
if(j>=n)t1[j]=val[l];
}
l=1,r=1;
for(int j=1;j<=a;j++)
{
while(l<r&&val[r-1]<=mx[j][i])r--;
val[r]=mx[j][i];pos[r]=j;r++;
if(pos[l]==j-n)l++;
if(j>=n)t2[j]=val[l];
}
for(int i=n;i<=a;i++)ans=min(ans,t2[i]-t1[i]);
}
printf("%d\n",ans);
}
int main()
{
a=read();b=read();n=read();
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
v[i][j]=read();
pre();
solve();
return 0;
}
小结:单调队列是优化dp的一种比较优秀的手段。而且好写好调,比什么单调栈强多了... ...
[bzoj1047][HAOI2007]理想的正方形_动态规划_单调队列的更多相关文章
- [luoguP2216] [HAOI2007]理想的正方形(二维单调队列)
传送门 1.先弄个单调队列求出每一行的区间为n的最大值最小值. 2.然后再搞个单调队列求1所求出的结果的区间为n的最大值最小值 3.最后扫一遍就行 懒得画图,自己体会吧. ——代码 #include ...
- [luogu2216 HAOI2007] 理想的正方形 (2dST表 or 单调队列)
题目描述 有一个ab的整数组成的矩阵,现请你从中找出一个nn的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表示a,b,n的值 第二行至第a ...
- BZOJ1047: [HAOI2007]理想的正方形 [单调队列]
1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2857 Solved: 1560[Submit][St ...
- bzoj千题计划215:bzoj1047: [HAOI2007]理想的正方形
http://www.lydsy.com/JudgeOnline/problem.php?id=1047 先用单调队列求出每横着n个最大值 再在里面用单调队列求出每竖着n个的最大值 这样一个位置就代表 ...
- BZOJ1047[HAOI2007]理想的正方形——二维ST表
题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非 ...
- BZOJ1047: [HAOI2007]理想的正方形
传送门 蛤省省选果然水啊,我这种蒟蒻都能一遍A. 横向纵向维护两个单调队列,做两次求最大和最小的,总复杂度$O(NM)$ 码农题,考察代码实现能力 //BZOJ 1047 //by Cydiater ...
- [BZOJ1047][HAOI2007]理想的正方形(RMQ+DP)
题意 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 思路 RMQ求 再DP 代码 #include<cstdio> #i ...
- 【单调队列】bzoj1047 [HAOI2007]理想的正方形
先把整个矩阵处理成b[n][m-K+1].c[n][m-K+1]大小的两个矩阵,分别存储每行每K个数中的最大.最小值,然后再通过b.c处理出d.e分别表示K*K大小的子矩阵中的最大.最小值即可.单调队 ...
- [BZOJ1047][HAOI2007]理想的正方形 二维单调队列
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1047 我们对每矩阵的一列维护一个大小为$n$的单调队列,队中元素为矩阵中元素.然后扫描每一 ...
随机推荐
- poj1200Crazy Search(hash)
题目大意 将一个字符串分成长度为N的字串.且不同的字符不会超过NC个.问总共有多少个不同的子串. /* 字符串hash O(n)枚举起点 然后O(1)查询子串hash值 然后O(n)找不一样的个数 ...
- ubuntu 更显列表 [Connecting to archive.ubuntu.com (2001:67c:1360:8001::21)] 超时的解决方法
问题描述: 在使用apt-get update 时更行列表,显示[Connecting to archive.ubuntu.com (2001:67c:1360:8001::21)]超时 分析: 我已 ...
- Centos 7 安装google 浏览器(yum 方式)
过程: 1 vim /etc/yum/repo.s/google_chrome.repo 2 添加如下内容: [google-chrome] name=google-chrome ...
- 51nod 1340 差分约束
思路: 带未知量的Floyd 很强 http://yousiki.net/index.php/archives/87/ //By SiriusRen #include <bits/stdc++. ...
- Vue初识:一个前端萌新的总结
一.前言 时隔三年,记得第一次写博客还是2015年了,经过这几年的洗礼,我也从一个后端的小萌新变成现在略懂一点点知识的文青.如今对于前端的东东也算有一知半解,个人能力总的来说,也能够独立开发产品级项目 ...
- Linux查找目录下的按时间过滤的文件
在维护项目中,有时会指定都一些条件进行过滤文件,并对该批文件进行操作:这时我们将使用shell命令进行操作:直接上代码 #!/bin/sh #BEGIN #`find ./ ! -name " ...
- 简单的KKL诊断线~~~自己在家都可以制作obd诊断接口了 ~~
简单的KKL诊断线~~~自己在家都可以制作~~ 适合bmw 07年以前的车型,因为新的车型使用D-can作为诊断接口,所以不能再使用kkl诊断接口不过SB开头的宝马3系还是可以使用的 更多内容欢迎查看 ...
- jQuery实现页面锚点滚动效果
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Java class对象说明 Java 静态变量声明和赋值说明
先看下JDK中的说明: java.lang.Object java.lang.Class<T> Instances of the class Class represent cla ...
- 剔除重复jar包,查找重复类
作为程序员,没有遇到过jar包冲突,不是你幸运,就是你还年轻. jar包冲突有着无穷的魔力,一提到就会有说不完的怨愤,道不清的忧伤,这都是内伤.jar 包冲突就像深藏地底的地雷,看上去平常无奇,一切是 ...