首页 > 其他分享 >理想的正方形 题解

理想的正方形 题解

时间:2024-02-22 09:03:51浏览次数:30  
标签:理想 int 题解 矩阵 最小 long 正方形 dmi 1005

题目描述

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

输入格式

第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每 行相邻两数之间用一空格分隔。 100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100

输出格式

仅一个整数,为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

题解

拿到本题,我们很容易想到遍历a * b矩阵中每个n * n的子矩阵并分别找出极差,最后输出最小的那个;

但很明显会TLE,于是需要换思路;

我们发现,TLE的根本在于循环次数太多,为什么循环次数会多呢?因为我们是基于二维来处理的这个问题,倘若将此问题转化成一个或几个一维的问题,就可以得到正解;

考虑每个n * n的子矩阵,我们发现,找最大值必须满足在这n行和n列都最大,最小也一样;

如何实现在这n行和n列都最大呢? 要在一维的前提下实现它,我们可以先求行再求列,先预处理出一个数组ma[i][j]代表第i行前j个元素中的最大值,mi[i][j]代表第i行前j个元素中的最小值,再以这个ma数组为基准找每一列的最大(最小)值,这样就可以做到在每个n * n的子矩阵的右下角存储此矩阵的最大值和最小值了;

为什么此做法不会TLE呢,因为

1.他是在一维基础上实现的;

2.找最大(最小)值必须满足在这n行和n列都最大(最小),所以如果某个数在一行都不是最大(最小)值的话,那么它也不是这个n * n的矩阵的最大(最小)值,上述思路优化掉了这些数,所以不会TLE;

对于找最大(最小)值,如果遍历又会超时,这里采用单调队列优化,找最小值就维护一个单调递增队列,找最大值就维护一个单调递减序列,每次记录队首元素即可;

代码

#include <iostream>
#include <deque>
using namespace std;
int n, m, b;
int a[1005][1005];
deque<int> dmi;
deque<int> dma;
long long ma[1005][1005];
long long mi[1005][1005];
long long ans;
int main() {
	cin >> n >> m >> b;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
		}
	}
	ans = 0x3f3f3f3f;
	for (int i = 1; i <= n; i++) {
		dmi.clear();
		dma.clear();
		for (int j = 1; j <= m; j++) {
			while(!dmi.empty() && a[i][dmi.back()] >= a[i][j]) {
				dmi.pop_back();
			}
			dmi.push_back(j);
			while(!dmi.empty() && dmi.front() <= j - b) dmi.pop_front();
			mi[i][j] = a[i][dmi.front()];
			while(!dma.empty() && a[i][dma.back()] <= a[i][j]) {
				dma.pop_back();
			}
			dma.push_back(j);
			while(!dma.empty() && dma.front() <= j - b) dma.pop_front(); //注意这一行和下一行的先后顺序;
			ma[i][j] = a[i][dma.front()];
		}
	}
	for (int j = 1; j <= m; j++) {
		dmi.clear();
		dma.clear();
		for (int i = 1; i <= n; i++) {
			while(!dmi.empty() && mi[dmi.back()][j] >= mi[i][j]) {
				dmi.pop_back();
			}
			dmi.push_back(i);
			while(!dmi.empty() && dmi.front() <= i - b) dmi.pop_front();
			while(!dma.empty() && ma[dma.back()][j] <= ma[i][j]) { //从横向更新的基础上纵向更新;
				dma.pop_back();
			}
			dma.push_back(i);
			while(!dma.empty() && dma.front() <= i - b) dma.pop_front();
			if (i >= b && j >= b) ans = min(ans, ma[dma.front()][j] - mi[dmi.front()][j]); //只有能构成一个子矩阵时才能找ans;
		}
	}
	cout << ans;
	return 0;
}

后记:这个题还有一种模拟退火做法,这里不再细讲;

标签:理想,int,题解,矩阵,最小,long,正方形,dmi,1005
From: https://www.cnblogs.com/PeppaEvenPig/p/18026564

相关文章

  • P5344 【XR-1】逛森林 题解
    题目链接:逛森林很早就想写写倍增优化建图,尤其是这题,奈何之前知识点没点够,本题线段树优化建图要优一些,不再赘述,没注意\(m\)是\(1e6\),挂了\(n\)多发才发现。后续再详细讲解倍增优化建图,这里简述本题做法。倍增优化建图其实和线段树优化建图恰不多的思想,为倍增求\(LCA\)的每......
  • 2024年2月21号题解
    106.从中序与后序遍历序列构造二叉树力扣题目链接解题思路找到根节点在中序序列的位置计算左子树的节点个数开辟一个节点,并把根节点的值赋值给这个节点根节点的左孩子和右孩子重复上面几个步骤代码实现/***Definitionforabinarytreenode.*structTreeNode{......
  • [BZOJ1047][HAOI2007][AcWing1091]理想的正方形(单调队列)
    此题的数据相当大,暴力的显然过不了,即使是O(abn)的算法也会超时,所以只能考虑O(ablogn)或O(ab)的算法。50分暴力#include<bits/stdc++.h>usingnamespacestd;intn,a,b,m[1001][1001];intdx(intx,inty){ intmaxn=0,minn=0x7fffffff; for(inti=x;i<=x+n-1;++i){ for(in......
  • Day-7 模拟赛题解
    Day-7模拟赛题解S+N---【玄英计划】---2月21日---模拟测#3【补题】-比赛-梦熊联盟T1数据点3-5枚举每一个问号对应的字母Kmp,把s当作模式串匹配T\(O(26^k|T|)\),k是?的个数代码(我也不知道为啥T了,鸽着)正解有种被诈骗了的感觉根据期望的可加性,答案等于......
  • P10064 [SNOI2024] 公交线路 题解
    非常好题目。思路可以发现限制最严的一定是两个叶子的联通性。我们不妨把一个叶子向外起到联通性作用的路径称为有用的路径。也就是这个叶子走这条路径一定可以两步以内到达任意点。这个路径集合有什么作用呢。有一个性质:整个集合的路径的交最终会形成一个连通块。那么我们......
  • Atm/抢掠计划——题解
    题目描述样例671223352441266510128161514435647解析题目明显是最长路,可以用spfa求最长路,但数据范围5e5明显不允许,所以我们可以用tarjan优化一下,然后这就变成了一道tarjan板子题,先用tarjan缩点,点权为几个点之和,把所有点再存到一个数组中,再按......
  • 洛谷P4447题解
    md这篇反正不交题解的,随便写,不管它格式题意简化下,给你N个数,求出连续值分组人数最小的那组的人数最大值。这个题目还挺经典的,原本23年8月份过了到现在来又不会了(划掉,bushi对于这种,很容易想到的是输入,之后排序,然后分组这种模板就不多说了,就在我24年2月份重温这道题再打一遍代码......
  • 1 c++算法题解析-两个数之和
    //给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。//你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。//你可以按任意顺序返回答案。//示例1:////输入:nums=[2,7,......
  • ARC111B Reversible Cards 题解 (套路题)
    考虑将\(a_i,b_i\)之间连边,发现题目可以被转化为给定一个图,要求对于每条边将其一个顶点染色,问最多能将多少个点染色。于是我们对于每个连通块分开来考虑。对于一个连通块,注意到我们不能将每个顶点染色当且仅当这个连通块是树,且此时可以染色的定点数量为连通块大小减一,如下:如......
  • blocks——题解
    题目描述解析对于这道题,他要求大于k的数进行操作,所以直接让每个数减k,然后用前缀和维护一下与0比较就可以了,因为一段区间和的平均值大于k的话,那么这就是一个合法区间,即为操作后的这个区间和大于0,我们可以用一个单调递减栈去维护,先把比0小的推入栈中,因为要求最大区间,所以边界......