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

题目描述

有一个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

跑两遍DP,第一遍处理出行i内以j为端点的长度为n的区间内的最大值和最小值。

第二遍DP,根据之前处理出的一维区间最值,DP出二维区间最值。

然后枚举区间端点,找最优解。

需要用单调队列优化

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 using namespace std;
 9 const int mxn=1010;
10 int read(){
11     int x=0,f=1;char ch=getchar();
12     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
13     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
14     return x*f;
15 }
16 int mp[mxn][mxn];
17 int fmx[mxn][mxn],fmi[mxn][mxn];
18 int dpmx[mxn][mxn],dpmi[mxn][mxn];
19 int a,b,n;
20 void work(){
21
22 }
23 int q1[mxn],hd1=0,tl1=0;
24 int q2[mxn],hd2=0,tl2=0;
25 int main(){
26     a=read();b=read();n=read();
27     int i,j;
28     memset(fmi,0x3f,sizeof fmi);
29     for(i=1;i<=a;i++){
30         hd1=hd2=1;
31         tl1=tl2=0;
32         for(j=1;j<=b;j++){
33             mp[i][j]=read();
34             while(hd1<=tl1 && j-q1[hd1]>=n)hd1++;
35             while(hd1<=tl1 && mp[i][j]>=mp[i][q1[tl1]]) tl1--;
36             q1[++tl1]=j;
37             fmx[i][j]=mp[i][q1[hd1]];
38             //max
39             while(hd2<=tl2 && j-q2[hd2]>=n)hd2++;
40             while(hd2<=tl2 && mp[i][j]<=mp[i][q2[tl2]]) tl2--;
41             q2[++tl2]=j;
42             fmi[i][j]=mp[i][q2[hd2]];
43             //min
44         }
45     }
46     memset(dpmi,0x3f,sizeof dpmi);
47     hd1=hd2=1;tl1=tl2=0;
48     for(j=1;j<=b;j++){
49         hd1=hd2=1;tl1=tl2=0;
50         for(i=1;i<=a;i++){
51             while(hd1<=tl1 && i-q1[hd1]>=n)hd1++;
52             while(hd1<=tl1 && fmx[i][j]>=fmx[q1[tl1]][j])tl1--;
53             q1[++tl1]=i;
54             dpmx[i][j]=fmx[q1[hd1]][j];
55
56             while(hd2<=tl2 && i-q2[hd2]>=n)hd2++;
57             while(hd2<=tl2 && fmi[i][j]<=fmi[q2[tl2]][j])tl2--;
58             q2[++tl2]=i;
59             dpmi[i][j]=fmi[q2[hd2]][j];
60
61         }
62     }
63     int ans=0x3f3f3f3f;
64     for(i=n;i<=a;i++)
65      for(j=n;j<=b;j++){
66          ans=min(ans,dpmx[i][j]-dpmi[i][j]);
67      }
68     printf("%d\n",ans);
69     return 0;
70 }
时间: 2024-10-27 11:38:23

洛谷P2216 [HAOI2007] 理想的正方形的相关文章

洛谷OJ 2216 理想的正方形 单调队列(二维)

https://www.luogu.org/problem/show?pid=2216 题意:给出a*b矩形 从中找到一个n*n正方形,其(最大值-最小值之差)最小,a,b<=1e3,n<=100暴力枚举正方形右下角,如何快速算出其最大值和最小值?先用单调队列预处理出ma[i][j] 表示(i,j)以第i行j列结尾长度为n的最大值/在枚举列之后,对同一个列,由于已经知道该列 每行长度为n的最值 则在次利用单调队列,从上往下扫描行,求出(i,j)为右下角的矩形的最值即可 #include <

P2216 [HAOI2007]理想的正方形 - 单调队列

这种矩形问题常用单调队列优化枚举(通过贪心取最优降低了一个维度的枚举) 推荐这道题也要做一做:[ZJOI2007]棋盘制作 单调队列的空间记得开大点! 反正内存够用 注意,这题正方形边长是固定的! 暴力算法是枚举上边界所在的行,左边界所在的列,通过这两个个信息确定一个正方形,然后预处理出一行中从第i个点到i+n个点的最值,再扫一遍这个正方形的行,复杂度是N^3 预处理的时候,复杂度也是N^3...考虑用单调队列来维护,枚举到一行,看做一个序列,求长度为n的区间最值,就是一个滑动窗口,如果不大明白

P2216 [HAOI2007]理想的正方形(二维RMQ)

题目描述 有一个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

P2216 [HAOI2007]理想的正方形

题目描述 有一个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

luogu P2216 [HAOI2007]理想的正方形

二维RMQ问题模板...(虽然我用单调队列加一维RMQ过的,,,但这个更方便一些,就再拿出来写写..跑的还快一点..) 和一维差不多,只不过需要比较四个区域罢了.. g[i][j][k]=max(g[i][j][k-1],max(g[i+(1<<(k-1))][j][k-1],max(g[i][j+(1<<(k-1))][k-1],g[i+(1<<(k-1))][j+(1<<(k-1))][k-1]))); 额,就是这样.. 上代码. #include<

[BZOJ1047][HAOI2007]理想的正方形

1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 3481  Solved: 1917 [Submit][Status][Discuss] Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值 的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每 行相邻

【BZOJ 1047】 [HAOI2007]理想的正方形

1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1685  Solved: 891 [Submit][Status] Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.

RAM——[HAOI2007]理想的正方形

题目:[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

HAOI2007 理想的正方形 单调队列

单调队列 by   GeneralLiu 滑动窗口是比较裸的单调队列 理想的正方形   就拔高了一个层次(多了一维) 有一个a*b的整数组成的矩阵 现请你从中找出一个n*n的正方形区域 使得该区域所有数中的最大值和最小值的差最小 只写MAX了,MIN一个道理,懒 不写了 先横着跑单调队列 维护许多长度为 n 的 横着的MAX 存在数组 map1[][] 中 再对数组 map1[][] 竖着跑单调队列 就维护了 许多 n*n 的 矩阵的MAX MIN同理 在竖着跑单调队列时 顺便MAX 与 MIN