• [HAOI2007]理想的正方形


    标签: 单调队列


    题目描述

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

    输入格式:

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

    输出格式:

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

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

    分析

      先枚举正方形所在的行,确定行之后,用滑动窗口分别求出窗口中的最大和最小值.

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    const int maxn=1050;
    const int inf=0x3f3f3f3f;
    int s[maxn][maxn],a,b,n;
    struct Queue
    {
    	int q[maxn],t,h;
    	Queue(){
    		t=0,h=1;
    	}
    	void push(int x,int y,int f=1){
    		while(t-h+1>=1&&s[q[t]][y]*f>=s[x][y]*f) t--;
    		q[++t]=x;
    	}
    	void pop(int x){
    		while(t-h+1>=1&&q[h]<x) h++;
    	}
    	int top(){
    		return q[h];
    	}
    }m[maxn],M[maxn];
    
    int main(int argc, char const *argv[])
    {
    	scanf("%d%d%d", &a,&b,&n);
    	for (int i = 0; i < a; ++i)
    	{
    		for (int j = 0; j < b; ++j)
    		{
    			scanf("%d", &s[i][j]);
    		}
    	}
    	int ans=inf;
    	for (int i = 0; i+n <= a; ++i)
    	{
    		if(i==0)
    			for (int j = 0; j < b; ++j)
    			{
    				for (int k = 0; k < n; ++k)
    				{
    					m[j].push(k,j);
    					M[j].push(k,j,-1);
    				}
    			}
    		else
    			for (int j = 0; j < b; ++j)
    			{
    				m[j].pop(i),m[j].push(i+n-1,j);
    				M[j].pop(i),M[j].push(i+n-1,j,-1);
    			}
    		int h=1,t=0,X[maxn],Y[maxn];
    		int hh=1,tt=0,XX[maxn],YY[maxn];
    		for (int j = 0; j+n <= b; ++j)
    		{
    			if(j==0){
    				for (int k = j; k < j+n; ++k)
    				{
    					int x=m[k].top();
    					while(t-h+1>=1&&s[X[t]][Y[t]]>=s[x][k]) t--;
    					X[++t]=x,Y[t]=k;
    
    					x=M[k].top();
    					while(tt-hh+1>=1&&s[XX[tt]][YY[tt]]<=s[x][k]) tt--;
    					XX[++tt]=x,YY[tt]=k;
    				}
    			}
    			else{
    				int x=m[j+n-1].top();
    				while(t-h+1>=1&&s[X[t]][Y[t]]>=s[x][j+n-1]) t--;
    				X[++t]=x,Y[t]=j+n-1;
    
    				x=M[j+n-1].top();
    				while(tt-hh+1>=1&&s[XX[tt]][YY[tt]]<=s[x][j+n-1]) tt--;
    				XX[++tt]=x,YY[tt]=j+n-1;
    			}
    			while(Y[h]<j) h++;
    			while(YY[hh]<j) hh++;
    			ans=min(ans,s[XX[hh]][YY[hh]]-s[X[h]][Y[h]]);
    		}
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    解析大型.NET ERP系统 20条数据库设计规范
    vi显示行号
    shell awk
    Linux使用Shell脚本实现ftp的自动上传下载
    MySQL Replication的Reset slave重置命令
    怎么样调整FreeBSD时区问题
    Basic Memory Structures
    States of Integrity Constraints
    Merging into a Table: Example
    oracle 单独开始一个事物的写法 。
  • 原文地址:https://www.cnblogs.com/sciorz/p/9050549.html
Copyright © 2020-2023  润新知