题目描述

有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

输入输出格式

输入格式:

第一行为3个整数,分别表示a,b,n的值

第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。

输出格式:

仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。

输入输出样例

输入样例#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

题意:

给定一个a*b的矩阵,找一个n*n的正方形,使得正方形里最大值和最小值之差最小。

思路:

我们可以预处理出每一个n*n的正方形的最大最小值分别是多少,然后暴力跑一遍找到最小值就可以了。

先处理横着的,用单调队列来维护。刚开始一直写不对,因为队列中应该存的是位置的下标而不是直接存值,因为head++的时候比较的是下标的距离,而我刚开始直接比较了tail和head也就是队列里的元素个数。

然后按照同样的方法,在行处理好的基础上处理列。

发现写单调队列的套路就是。比如我们要建一个存最大值的,那我们应该比较队尾和当前值的关系。

如果队尾比当前值小就要一直tail--

然后删去不满足区间约束的队头的值。

然后每次取的应该是队头的元素。

 #include <iostream>
#include <set>
#include <cmath>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define inf 0x7f7f7f7f const int maxn = ;
int a, b, n;
LL grid[maxn][maxn];
LL row_big[maxn][maxn], col_big[maxn][maxn], row_small[maxn][maxn], col_small[maxn][maxn];
LL que_big[maxn], que_small[maxn]; int main()
{
scanf("%d%d%d", &a, &b, &n);
for(int i = ; i <= a; i++){
for(int j = ; j <= b; j++){
scanf("%lld", &grid[i][j]);
row_big[i][j] = col_big[i][j] = -;
row_small[i][j] = col_small[i][j] = LLONG_MAX;
}
} //cout<<endl;
int tail_b = , tail_s = , head_b = , head_s = ;
for(int i = ; i <= a; i++){
tail_b = tail_s = ;
head_b = head_s = ;
for(int j = ; j <= b; j++){
//row_big[i][j] = max(que_big[tail_b], grid[i][j]);
//cout<<row_big[i][j]<<" ";
while(grid[i][que_big[tail_b]] <= grid[i][j] && head_b <= tail_b){
tail_b--;
}
que_big[++tail_b] = j;
while(j - que_big[head_b] >= n){
head_b++;
}
row_big[i][j] = grid[i][que_big[head_b]]; //row_small[i][j] = min(que_small[tail_s], grid[i][j]);
while(grid[i][que_small[tail_s]] >= grid[i][j] && head_s <= tail_s){
tail_s--;
}
que_small[++tail_s] = j;
while(j - que_small[head_s] >= n){
head_s++;
}
row_small[i][j] = grid[i][que_small[head_s]];
}
//cout<<endl;
} /*cout<<endl;
for(int i = 1; i <= a; i++){
for(int j = n; j <= b; j++){
cout<<row_big[i][j]<<" ";
}
cout<<endl;
}*/ for(int j = ; j <= b; j++){
tail_b = tail_s = ;
head_b = head_s = ;
for(int i = ; i <= a; i++){
//col_big[i][j] = max(que_big[tail_b], row_big[i][j]);
while(row_big[que_big[tail_b]][j] <= row_big[i][j] && head_b <= tail_b){
tail_b--;
}
que_big[++tail_b] = i;
while(i - que_big[head_b] >= n){
head_b++;
}
col_big[i][j] = row_big[que_big[head_b]][j]; //col_small[i][j] = min(que_small[tail_s], row_small[i][j]);
while(row_small[que_small[tail_s]][j] >= row_small[i][j] && head_s <= tail_s){
tail_s--;
}
que_small[++tail_s] = i;
while(i - que_small[head_s] >= n){
head_s++;
}
col_small[i][j] = row_small[que_small[head_s]][j];
}
} /*cout<<endl;
for(int i = n ;i <= a; i++){
for(int j = n; j <= b; j++){
cout<<col_big[i][j]<<" ";
}
cout<<endl;
}*/ LL ans = LLONG_MAX;
for(int i = n; i <= a; i++){
for(int j = n; j <= b; j++){
ans = min(ans, col_big[i][j] - col_small[i][j]);
}
}
printf("%lld\n", ans);
return ;
}

洛谷P2216 理想的正方形的更多相关文章

  1. 洛谷P2216 理想的正方形(单调队列)

    洛谷P2216 理想的正方形 题目链接 思路: 直接暴力显然不可行,可以发现每一个矩形向右边扩展时是一列一列增加,于是可以想到单调队列,用数组来维护当前每列的最大值.因为行也有限制,所以还要用一个单调 ...

  2. 洛谷 [P2216] 理想的正方形

    二维单调队列 先横向跑一边单调队列,记录下每一行长度为n的区间的最值 在纵向跑一边单调队列,得出结果 注意,mi要初始化为一个足够大的数 #include <iostream> #incl ...

  3. 洛谷P2216: [HAOI2007]理想的正方形 单调队列优化DP

    洛谷P2216 )逼着自己写DP 题意: 给定一个带有数字的矩阵,找出一个大小为n*n的矩阵,这个矩阵中最大值减最小值最小. 思路: 先处理出每一行每个格子到前面n个格子中的最大值和最小值.然后对每一 ...

  4. 洛谷 P2216 [HAOI2007]理想正方形

    洛谷 巨说这是一道单调队列好题,但是我并不是用单调队列做的诶. 如果往最暴力的方向去想,肯定是\(n^3\)的\(dp\)了. \(f[i][j][k]\)代表当前正方形的左上角定点是\((i,j)\ ...

  5. 洛谷 P2216 [HAOI2007]理想的正方形

    P2216 [HAOI2007]理想的正方形 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一 ...

  6. 【洛谷P2216】[HAOI2007]理想的正方形

    理想的正方形 [题目描述] 一个a*b的矩阵,从中取一个n*n的子矩阵,使所选矩阵中的最大数与最小数的差最小. 思路: 二维的滑动窗口 对于每行:用一个单调队列维护,算出每个长度为n的区间的最大值和最 ...

  7. 洛谷 P2216 [HAOI2007]理想的正方形 || 二维RMQ的单调队列

    题目 这个题的算法核心就是求出以i,j为左上角,边长为n的矩阵中最小值和最大值.最小和最大值的求法类似. 单调队列做法: 以最小值为例: q1[i][j]表示第i行上,从j列开始的n列的最小值.$q1 ...

  8. 洛谷P2216 HAOI2007 理想的正方形 (单调队列)

    题目就是要求在n*m的矩形中找出一个k*k的正方形(理想正方形),使得这个正方形内最值之差最小(就是要维护最大值和最小值),显然我们可以用单调队列维护. 但是二维平面上单调队列怎么用? 我们先对行处理 ...

  9. 【DP】【单调队列】洛谷 P2216 [HAOI2007]理想的正方形 题解

        算是单调队列的复习吧,不是很难 题目描述 有一个$a\times b$的整数组成的矩阵,现请你从中找出一个$n\times n$的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 ...

随机推荐

  1. 1、一、Introduction(入门): 0、Introduction to Android(引进到Android)

    一.Introduction(入门) 0.Introduction to Android(引进到Android) Android provides a rich application framewo ...

  2. Waf-Bypass-Learning

    WAF Bypass 综合篇: WAF攻防研究之四个层次Bypass WAF Bypass WAF Cookbook - MayIKissYou My Waf Bypass Series Articl ...

  3. sharepoint权限操作(记录以备忘)

    using Microsoft.SharePoint; using System; using System.Collections.Generic; using System.Linq; using ...

  4. 【RF库测试】算法运算

  5. 如何删除一个CSDN上自己上传的资源

    原文地址:http://www.xuebuyuan.com/1875216.html 昨天晚上进行测试,上传了一个压缩包和大家分享,测试完成后,为了不想给被测试的公司造成伤害,决定把上传的包删除,结果 ...

  6. 编译poco-1.7.8

    运行build_vs140.cmd,运行之前可以修改一些参数,例如编译64位 buildwin 140 build shared both x64 nosamples notests devenv 修 ...

  7. java的两种冒泡算法

    所谓的冒泡算法,就是给数组进行排序,可以根据以小到大的顺序,也可以根据以小到大的顺序,在数组的封装类java.util.Arrays通过sort方法进行按升序的排序.那不用类的话怎么进行呢? 思路一: ...

  8. Spring系列之IOC容器

    一.概述 IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象之间的依赖.应用程序无需直接在代码中new 相关的对象,应用程序由IOC容器进行组装.在S ...

  9. PHP文件包含漏洞攻防实战

    本文对PHP文件包含漏洞的形成.利用技巧及防范进行了详细分析,并通过一个真实案例演示了如何利用PHP文件包含漏洞对目标网站进行渗透测试,最终成功获取到网站的WebShell. PHP是一种非常流行的W ...

  10. OpenCV——轮廓面积及长度计算

    计算轮廓面积: double contourArea(InputArray contour, bool oriented=false ) InputArray contour:输入的点,一般是图像的轮 ...