P2216 [HAOI2007]理想的正方形
题目描述
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
输入输出格式
输入格式:
第一行为3个整数,分别表示a,b,n的值
第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。
输出格式:
仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。
输入输出样例
说明
问题规模
(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表的变式:
dp[i][j][k]:代表以坐标(i,j)左上角,边长为2^k的正方形的最大差值
(类比线性ST表,它更新的方法是:一个区间取出两个相同长度(2^n)部分)
所以这里用来更新的方法应该是:一个正方形区间取出四个相同面积部分
dp[i][j][k]=opt(dp[i][j][k-1],dp[i][j+(1<<(k-1))][k-1],dp[i+(1<<(k-1))][j][k-1],dp[i+(1<<(k-1))][j+(1<<(k-1))][k-1]);
1.三维
正常纯矩阵ST表
#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
typedef long long ll;
#define inf 2147483647
#define ri register int
#define getchar() (Ss==Tt&&(Tt=(Ss=BB)+fread(BB,1,1<<15,stdin),Ss==Tt)?EOF:*Ss++)
char BB[ << ], *Ss = BB, *Tt = BB;
inline int read()
{
int x=;
int ch=getchar(),f=;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-')
{
f=-;
ch=getchar();
}
while (isdigit(ch))
{
x=(x<<)+(x<<)+ch-'';
ch=getchar();
}
return x*f;
} int a,b;
int n;
int S[maxn][maxn][];
int T[maxn][maxn][];
int l,K; int query(int x1,int y1,int x2,int y2)
{
int t=<<l;
int MIN=min(min(S[x1][y1][l],S[x2-t+][y1][l]),
min(S[x1][y2-t+][l],S[x2-t+][y2-t+][l])
);
int MAX=max(max(T[x1][y1][l],T[x1][y2-t+][l]),
max(T[x2-t+][y2-t+][l],T[x2-t+][y1][l])
);
return MAX-MIN;
} int main()
{
memset(S,0x3f,sizeof(S));
// freopen("test.txt","r",stdin);
a=read(),b=read(),n=read();
for(int i=; i<=a; i++)
for(int j=; j<=b; j++)
S[i][j][]=T[i][j][]=read(); K=log2(min(a,b));
l=log2(n); for(int k=; k<=K; k++)
{
int t=<<(k-);
for(int i=; i<=a-t; i++)
for(int j=; j<=b-t; j++)
{
S[i][j][k]=min(min(S[i][j][k-],S[i][j+t][k-]),
min(S[i+t][j][k-],S[i+t][j+t][k-])
);
T[i][j][k]=max(max(T[i][j][k-],T[i][j+t][k-]),
max(T[i+t][j][k-],T[i+t][j+t][k-])
);
}
}
int ans=inf;
for(int i=; i<=a-n+; i++)
for(int j=; j<=b-n+; j++)
{
// cout<<query(i,j,i+n-1,j+n-1)<<endl;
ans=min(ans,query(i,j,i+n-,j+n-));
}
cout<<ans; return ;
}
2. 二维优化
仔细发现显然可以压成二维,省去k长度那一维,不影响结果
在三维的基础上,令dp[i][j]=min(dp[i][j][0~k]) k为log2(n)
#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
typedef long long ll;
#define inf 2147483647
#define ri register int
#define getchar() (Ss==Tt&&(Tt=(Ss=BB)+fread(BB,1,1<<15,stdin),Ss==Tt)?EOF:*Ss++)
char BB[ << ], *Ss = BB, *Tt = BB;
inline int read()
{
int x=;
int ch=getchar(),f=;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-')
{
f=-;
ch=getchar();
}
while (isdigit(ch))
{
x=(x<<)+(x<<)+ch-'';
ch=getchar();
}
return x*f;
} int a,b;
int n;
int S[maxn][maxn];
int T[maxn][maxn];
int l,K; int query(int x1,int y1,int x2,int y2)
{
int t=<<l;
int MIN=min(min(S[x1][y1],S[x2-t+][y1]),
min(S[x1][y2-t+],S[x2-t+][y2-t+])
);
int MAX=max(max(T[x1][y1],T[x1][y2-t+]),
max(T[x2-t+][y2-t+],T[x2-t+][y1])
);
return MAX-MIN;
} int main()
{
memset(S,0x3f,sizeof(S));
// freopen("test.txt","r",stdin);
a=read(),b=read(),n=read();
for(int i=; i<=a; i++)
for(int j=; j<=b; j++)
S[i][j]=T[i][j]=read(); l=log2(n); for(int k=; k<=l; k++)
{
int t=<<(k-);
for(int i=; i<=a-t; i++)
for(int j=; j<=b-t; j++)
{
S[i][j]=min(min(S[i][j],S[i][j+t]),
min(S[i+t][j],S[i+t][j+t])
);
T[i][j]=max(max(T[i][j],T[i][j+t]),
max(T[i+t][j],T[i+t][j+t])
);
}
}
int ans=inf;
for(int i=; i<=a-n+; i++)
for(int j=; j<=b-n+; j++)
{
// cout<<query(i,j,i+n-1,j+n-1)<<endl;
ans=min(ans,query(i,j,i+n-,j+n-));
}
cout<<ans; return ;
}
3.ST表+单调队列
先创线性的ST表得到每行的opt值,然后选择指定行数,再单调队列处理
mi[i][j][k]:代表第i行,从第j列向右长度为2^k范围中最小数
如果是线性的话qmi这里应该是由一个head,一个tail代替
但是这里是矩阵,还要考虑行的存在
qmi[i][1]:用来存真正最小数
qmi[i][0]:用来存横坐标,控制范围防止越界
#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
typedef long long ll;
#define inf 9999999999
#define re register inline int read()
{
int x=;
int ch=getchar(),f=;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-')
{
f=-;
ch=getchar();
}
while (isdigit(ch))
{
x=(x<<)+(x<<)+ch-'';
ch=getchar();
}
return x*f;
} //读优 int ma[maxn][maxn][],mi[maxn][maxn][];
int qma[maxn][],qmi[maxn][];
int n,m,t;
int ans=inf; //查询第k行的第x列到第y列的最大值
int queryma(int k,int x1,int x2)
{
int l=log2(x2-x1+);//刚好覆盖或大于x2-x1一半的2的幂指数
return max(ma[k][x1][l],ma[k][x2-(<<l)+][l]);
}
int querymi(int k,int x1,int x2)
{
int l=log2(x2-x1+);
return min(mi[k][x1][l],mi[k][x2-(<<l)+][l]);
} int main()
{
// freopen("test.txt","r",stdin);
n=read(),m=read(),t=read();
int l=log2(max(n,m));
fill(&mi[][][],&mi[maxn-][maxn-][],inf);
for(int i=; i<=n; i++)
for(int j=; j<=m; j++)
ma[i][j][]=mi[i][j][]=read();
for(int i=; i<=n; i++)
for(int k=; k<=l; k++)
{
int x=<<(k-);
for(int j=; j<=m-x; j++)
{
ma[i][j][k]=max(ma[i][j][k-],ma[i][j+x][k-]);
mi[i][j][k]=min(mi[i][j][k-],mi[i][j+x][k-]);
}
} //遍历列(找起点)
for(int i=; i<=m; i++)
{
if(i+t->m)break;
int h1=,h2=;
int t1=,t2=; //单调队列:每次寻找最具潜力的数,然后删掉那些没用的数
for(int j=; j<=n; j++)
{
int x=queryma(j,i,i+t-);//横向比较,询问第j行,取出(i~i+t-1)中最大数
while(x>=qma[t1][]&&h1<=t1)t1--;//这里是纵向比较
qma[++t1][]=x;
qma[t1][]=j;//同时记录行 x=querymi(j,i,i+t-);
while(x<=qmi[t2][]&&h2<=t2)t2--;
qmi[++t2][]=x;
qmi[t2][]=j; //为了满足这个正方形,横坐标小于(j-t)都不属于这个范围,所以h++,跳到单调队列的下一个点
if(j>=t)
{
while(j-t>=qma[h1][])h1++;
while(j-t>=qmi[h2][])h2++;
ans=min(ans,qma[h1][]-qmi[h2][]);
}
}
} cout<<ans;
return ;
}
P2216 [HAOI2007]理想的正方形的更多相关文章
- 洛谷 P2216 [HAOI2007]理想的正方形
P2216 [HAOI2007]理想的正方形 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一 ...
- P2216 [HAOI2007]理想的正方形 (单调队列)
题目链接:P2216 [HAOI2007]理想的正方形 题目描述 有一个 \(a\times b\)的整数组成的矩阵,现请你从中找出一个 \(n\times n\)的正方形区域,使得该区域所有数中的最 ...
- P2216 [HAOI2007]理想的正方形 方法记录
[HAOI2007]理想的正方形 题目描述 有一个 \(a \times b\) 的整数组成的矩阵,现请你从中找出一个 \(n \times n\) 的正方形区域,使得该区域所有数中的最大值和最小值的 ...
- 洛谷 P2216 [HAOI2007]理想的正方形 || 二维RMQ的单调队列
题目 这个题的算法核心就是求出以i,j为左上角,边长为n的矩阵中最小值和最大值.最小和最大值的求法类似. 单调队列做法: 以最小值为例: q1[i][j]表示第i行上,从j列开始的n列的最小值.$q1 ...
- 洛谷P2216 HAOI2007 理想的正方形 (单调队列)
题目就是要求在n*m的矩形中找出一个k*k的正方形(理想正方形),使得这个正方形内最值之差最小(就是要维护最大值和最小值),显然我们可以用单调队列维护. 但是二维平面上单调队列怎么用? 我们先对行处理 ...
- 【DP】【单调队列】洛谷 P2216 [HAOI2007]理想的正方形 题解
算是单调队列的复习吧,不是很难 题目描述 有一个$a\times b$的整数组成的矩阵,现请你从中找出一个$n\times n$的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 ...
- [P2216] [HAOI2007]理想的正方形 「单调队列」
思路:用单调队列分别维护行与列. 具体实现方法:是先用单调队列对每一行的值维护,并将a[][]每个区间的最大值,最小值分别存在X[][]和x[][]中. 那么X[][]与x[][]所存储的分别是1×n ...
- 洛谷P2216: [HAOI2007]理想的正方形 单调队列优化DP
洛谷P2216 )逼着自己写DP 题意: 给定一个带有数字的矩阵,找出一个大小为n*n的矩阵,这个矩阵中最大值减最小值最小. 思路: 先处理出每一行每个格子到前面n个格子中的最大值和最小值.然后对每一 ...
- P2216 [HAOI2007]理想的正方形(dp+单调队列优化)
题目链接:传送门 题目: 题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入输出格式 输入格式: 第一行为3个整数,分别表 ...
随机推荐
- python3.8 新特性
https://docs.python.org/3.8/whatsnew/3.8.html python 3.8的新功能本文解释了与3.7相比,python 3.8中的新特性. 有关完整的详细信息,请 ...
- 撩课-Web大前端每天5道面试题-Day1
1. var的变量提升的底层原理是什么? JS引擎的工作方式是: 1) 先解析代码,获取所有被声明的变量: 2)然后在运行.也就是说分为预处理和执行两个阶段. 变量提升:所有变量的声明语句都会被提升到 ...
- plsql 导出查询结果
点击青色按钮即可 说明: 会将查询到的所有数据导出到指定文件,并不是只导出下面列表显示的几行数据: 也不用点击"获取最后页"那个按钮. 注意: 当你选择导出为excel文件时, ...
- Httprunner学习
一.简介 HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份YAML/JSON脚本,即可实现自动化测试.性能测试.线上监控.持续集成等多种测试需求. 核心特性: 继 ...
- Python Word2Vec使用训练好的模型生成词向量
# 文本文件必须是utf-8无bom格式 from gensim.models.deprecated.word2vec import Word2Vec model = Word2Vec.load( ' ...
- SqlServer数据库设计一个字段的值是由其他字段运算结果所得
最近在做项目时,发现数据库的一些字段不能执行sql语句进行修改,仔细观察才发现,它是由其他字段运算结果所得.这样就不需程序员通过代码执行运算结果更新数据库,感觉很实用,而网上教材好像还挺少的,所以把教 ...
- Python3部分Print输出格式
print("Hello World!") #直接打印字符串 print('Hello World!') #对于python,单引号也可以表示字符串 name = 'Tom' #自 ...
- Zabbix添加Ping外网IP监控
1.先添加一个HOST,只填写IP即可,如10.1.1.1 2.选择一台客户端,新建item,如下: 3.新建trigger: 注:icmpping[<target>,<packet ...
- Linux之添加交换分区
Linux下的交换分区我们可以随意改变大小,如果说日常生活中分区不够用,今天我们来举个例子如何添加. 1.首先是使用dd命令创建一个空文件,这个空文件的大小就是你要继续添加的swap的大小,比如我这里 ...
- MySQL基础之 如何删除主键
我们在一个表中设置了主键之后,那么如何删除主键呢? 删除主键的语法是: ALTER TABLE TABLE_NAME DROP PRIMARY KEY; 在这里我们要考虑两种情况: 1.可以直接使用d ...