• luogu2216 二维ST表


    [HAOI2007]理想的正方形

    题目描述

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

    输入格式

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

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

    输出格式

    仅一个整数,为 \(a \times b\) 矩阵中所有“ \(n \times n\) 正方形区域中的最大整数和最小整数的差值”的最小值。

    样例 #1

    样例输入 #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,000,000,000\)

    \(20\%\) 的数据 \(2 \le a,b \le 100,n \le a,n \le b,n \le 10\)

    \(100\%\) 的数据 \(2 \le a,b \le 1000,n \le a,n \le b,n \le 100\)


    二维ST表,就是用来在二维表格中查找最大最小值。和ST表一样,都是倍增。
    初始化\(O(n^2\log n)\),每次查询\(O(1)\)
    初始化:
    f[i][j][k]表示(i,j)点左上角的边长为\(2^k\)的正方形区域内的最大值。
    f[i][j][k]=max(f[i][j][k-1],f[i-(1<<(k-1))][j][k-1],f[i][j-(1<<(k-1))][k-1],f[i-(1<<(k-1))][j-(1<<(k-1))][k-1])
    查询:
    fx[i][j][k]表示(i,j)点左上角的边长为k的正方形区域内的最大值。
    fx[i][j][k]=max(fx[i][j][lgk],fx[i-k+(1<<lgk)][j][lgk],fx[i][j-k+(1<<lgk)][lgk],fx[i-k+(1<<lgk)][j-k+(1<<lgk)][lgk])


    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1010;
    int sz[maxn][maxn],fx[maxn][maxn][12],fn[maxn][maxn][12];
    int a,b,n;
    int lg[maxn];
    int maxf(int a,int b,int c,int d)
    {
    	return max(max(a,b),max(c,d));
    }
    int minf(int a,int b,int c,int d)
    {
    	return min(min(a,b),min(c,d));
    }
    int main()
    {
    	scanf("%d%d%d",&a,&b,&n);
    	for(int i=1;i<=a;++i)
    	for(int j=1;j<=b;++j)
    	{
    		scanf("%d",&sz[i][j]);
    		fx[i][j][0]=fn[i][j][0]=sz[i][j];
    	}
    	
    	int tpn=min(a,b),tpx=max(a,b);
    	for(int i=2;i<=tpx;++i)lg[i]=lg[i/2]+1;
    	
    	for(int l=1;l<=lg[tpx];++l)
    		for(int i=(1<<l);i<=a;++i)
    			for(int j=(1<<l);j<=b;++j)
    			{
    				fn[i][j][l]=minf(fn[i][j][l-1],fn[i-(1<<(l-1))][j][l-1],fn[i][j-(1<<(l-1))][l-1],fn[i-(1<<(l-1))][j-(1<<(l-1))][l-1]);
    				fx[i][j][l]=maxf(fx[i][j][l-1],fx[i-(1<<(l-1))][j][l-1],fx[i][j-(1<<(l-1))][l-1],fx[i-(1<<(l-1))][j-(1<<(l-1))][l-1]);
    			}
    	
    	int ans=0x7fffffff,lgn=lg[n];
    	for(int x,y,i=n;i<=a;++i)
    		for(int j=n;j<=b;++j)
    		{
    			x=minf(fn[i][j][lgn],fn[i-n+(1<<lgn)][j][lgn],fn[i][j-n+(1<<lgn)][lgn],fn[i-n+(1<<lgn)][j-n+(1<<lgn)][lgn]);
    			y=maxf(fx[i][j][lgn],fx[i-n+(1<<lgn)][j][lgn],fx[i][j-n+(1<<lgn)][lgn],fx[i-n+(1<<lgn)][j-n+(1<<lgn)][lgn]);
    			ans=min(ans,y-x);
    		}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Hello World基于.net framework中CLR的执行
    MVN常用命令
    Git常用命令
    Markdown常用语法
    计算机专用英语词汇
    Windows DiskPart
    字符集过滤器
    SSHkey
    书名
    redis
  • 原文地址:https://www.cnblogs.com/gryzy/p/16577123.html
Copyright © 2020-2023  润新知