zoukankan      html  css  js  c++  java
  • P2216 [HAOI2007]理想的正方形

    Link

    题目描述

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

    输入格式

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

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

    输出格式

    仅一个整数,为 (a imes b) 矩阵中所有“ (n imes 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

    题解

    这道题有很多种做法。然鹅我却写了最复杂的二维单调队列,不仅难写,还难调。蓝瘦

    首先,我们可以求出以每个点为结尾的长度为 (n) 的区间中的最小值与最大值,也就是对每一行做一遍滑动窗口。

    之后,我们对每一列在跑一边滑动窗口,只不过这次是对我们对每一行做单调队列的结果做一遍单调队列。

    我们这一遍求出来的就是 以这个点为右下角,边长为 (n) 的这一块矩形中的最大值与最小值。

    你可以理解为,把 (n) 个长度为 (n) 的区间拼在了一起。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int ans = 2147483647;
    int n,m,k,a[1010][1010],q1[1010],q2[1010];
    int maxn[1010][1010],minn[1010][1010];
    inline int read()
    {
    	int s = 0,w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    	return s * w;
    }
    int main()
    {
    	n = read(); m = read(); k = read();
    	for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) a[i][j] = read();
    	for(int i = 1; i <= n; i++)
    	{
    		int l = 1, r = 0, L = 1, R = 0;
    		q1[++r] = 1; q2[++R] = 1;
    		for(int j = 2; j <= m; j++)//对每一行求一遍滑动窗口
    		{
    			while(l <= r && q1[l] <= j-k) l++;
    			while(L <= R && q2[L] <= j-k) L++;
    			while(l <= r && a[i][q1[r]] <= a[i][j]) r--;
    			while(L <= R && a[i][q2[R]] >= a[i][j]) R--;
    			q1[++r] = j; q2[++R] = j; 
    			maxn[i][j] = a[i][q1[l]];
    			minn[i][j] = a[i][q2[L]];	
    		}
    	}
    	for(int i = k; i <= m; i++)
    	{
    		int l = 1, r = 0, L = 1, R = 0;
    		q1[++r] = 1; q2[++R] = 1;
    		for(int j = 2; j <= n; j++)//在每一行的基础上在对每一列做一遍滑动窗口
    		{
    			while(l <= r && q1[l] <= j-k) l++;
    			while(L <= R && q2[L] <= j-k) L++;
    			while(l <= r && maxn[q1[r]][i] <= maxn[j][i]) r--;
    			while(L <= R && minn[q2[R]][i] >= minn[j][i]) R--;
    			q1[++r] = j; q2[++R] = j;
    			if(j >= k) ans = min(ans,maxn[q1[l]][i] - minn[q2[L]][i]);
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    基于asp.net(C#)MVC+前端bootstrap+ztree+lodash+jquery技术-Angel工作室通用权限管理
    java架构之-负载均衡-Ribbon 的使用
    docker采用Dockerfile安装jdk1.8案例
    Redis 模糊查询删除操作
    centos7.2安装及管理docker
    git 解决每次更新代码都要输入用户名密码的解决方案
    github上的版本和本地版本冲突的解决方法
    git命令之git mergetool vi非正常退出.swp删除不了的问题
    html-webpack-plugin详解
    Webpack友好的错误提示插件friendly-errors-webpack-plugin
  • 原文地址:https://www.cnblogs.com/genshy/p/13693795.html
Copyright © 2011-2022 走看看