浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

[bzoj 1047][HAOI2007]理想的正方形

传送门

Description

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

Input

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

Output

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

Sample Input

5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2

Sample Output

1
 
题解:
对于原矩阵每行维护两个单调队列(最大和最小)
然后对得到的max数组和min数组每列再次维护一个单调队列
四次单调队列就ok,弄清楚原理之后这个东西套模板就好
其实就是打一遍然后复制粘贴..
 
代码:
#include <cstdio>
#define ll int
#define inf 1<<30
#define max(x,y) x>y?x:y
#define min(x,y) x<y?x:y
#define abs(x) x>0?x:-x
inline void read(ll &x){
    x=0;ll f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    x*=f;
}
using namespace std;
#define N 1010
ll n,m,len;
ll a[N][N];
ll q1[N],q2[N];
ll MAX[N][N],MIN[N][N];
ll L1[N],L2[N],R1[N],R2[N],Q1[N][N],Q2[N][N];
ll ans=((1<<30)-1)<<1|1;
int main(){
    read(n);read(m);read(len);
    for(ll i=1;i<=n;i++){
        for(ll j=1;j<=m;j++){
            read(a[i][j]);
        }
    }
//  mt(L1,1);mt(L2,1);mt(R1,0);mt(R2,0);
    for(ll i=1;i<=m;i++)L1[i]=L2[i]=1,R1[i]=R2[i]=0;
    for(ll i=1;i<=n;i++){
        ll r1=0,l1=1,r2=0,l2=1;
        for(ll j=m;j>=1;j--){
            MAX[i][j]=MIN[i][j]=a[i][j];
            while(l1<=r1&&q1[l1]-j>=len)l1++;
            while(l2<=r2&&q2[l2]-j>=len)l2++;
            while(l1<=r1&&a[i][j]>a[i][q1[r1]])r1--;
            q1[++r1]=j;
            if(l1<=r1)MAX[i][j]=max(MAX[i][j],a[i][q1[l1]]);
            while(l2<=r2&&a[i][j]<a[i][q2[r2]])r2--;
            q2[++r2]=j;
            if(l2<=r2)MIN[i][j]=min(MIN[i][j],a[i][q2[l2]]);
        }
        for(ll j=m-len+1;j>=1;j--){
            while(L1[j]<=R1[j]&&i-Q1[j][L1[j]]>=len)L1[j]++;
            while(L2[j]<=R2[j]&&i-Q2[j][L2[j]]>=len)L2[j]++;
            while(L1[j]<=R1[j]&&MAX[i][j]>MAX[Q1[j][R1[j]]][j])R1[j]--;
            while(L2[j]<=R2[j]&&MIN[i][j]<MIN[Q2[j][R2[j]]][j])R2[j]--;
            Q1[j][++R1[j]]=i;Q2[j][++R2[j]]=i;
            if(i>=len){
                if(L1[j]<=R1[j]&&L2[j]<=R2[j]){
                    ans=min(ans,MAX[Q1[j][L1[j]]][j]-MIN[Q2[j][L2[j]]][j]);
                }
            }
        }
    }
    printf("%d\n",ans);
}

  

posted @ 2018-04-10 22:45  henry_y  阅读(176)  评论(0编辑  收藏  举报