题目描述

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

输入输出格式

输入格式:

 

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

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

 

输出格式:

 

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

 

线性ST表的变式:

dp[i][j][k]:代表以坐标(i,j)左上角,边长为2^k的正方形的最大差值
(类比线性ST表,它更新的方法是:一个区间取出两个相同长度(2^n)部分)
所以这里用来更新的方法应该是:一个正方形区间取出四个相同面积部分

P2216 [HAOI2007]理想的正方形

 


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[1 << 18], *Ss = BB, *Tt = BB;
inline int read()
{
    int x=0;
    int ch=getchar(),f=1;
    while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
    if (ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    while (isdigit(ch))
    {
        x=(x<<1)+(x<<3)+ch-'0';
        ch=getchar();
    }
    return x*f;
}

int a,b;
int n;
int S[maxn][maxn][11];
int T[maxn][maxn][11];
int l,K;

int query(int x1,int y1,int x2,int y2)
{
    int t=1<<l;
    int MIN=min(min(S[x1][y1][l],S[x2-t+1][y1][l]),
                min(S[x1][y2-t+1][l],S[x2-t+1][y2-t+1][l])
               );
    int MAX=max(max(T[x1][y1][l],T[x1][y2-t+1][l]),
                max(T[x2-t+1][y2-t+1][l],T[x2-t+1][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=1; i<=a; i++)
        for(int j=1; j<=b; j++)
            S[i][j][0]=T[i][j][0]=read();

    K=log2(min(a,b));
    l=log2(n);

    for(int k=1; k<=K; k++)
    {
        int t=1<<(k-1);
        for(int i=1; i<=a-t; i++)
            for(int j=1; j<=b-t; j++)
            {
                S[i][j][k]=min(min(S[i][j][k-1],S[i][j+t][k-1]),
                               min(S[i+t][j][k-1],S[i+t][j+t][k-1])
                              );
                T[i][j][k]=max(max(T[i][j][k-1],T[i][j+t][k-1]),
                               max(T[i+t][j][k-1],T[i+t][j+t][k-1])
                              );
            }
    }
    int ans=inf;
    for(int i=1; i<=a-n+1; i++)
        for(int j=1; j<=b-n+1; j++)
        {
//            cout<<query(i,j,i+n-1,j+n-1)<<endl;
            ans=min(ans,query(i,j,i+n-1,j+n-1));
        }
    cout<<ans;


    return 0;
}
View Code

相关文章: