BZOJ 1047 [HAOI2007]理想的正方形

1047: [HAOI2007]理想的正方形

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2054  Solved: 1091
[Submit][Status][Discuss]

Description

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

Input

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

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

HINT

 

问题规模

(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

 

Source

题解:太神了,膜郑爷%%%

首先看数据范围,很显然要求线性算法,那就是说只能扫一次喽,那就是说要O(1)维护喽,那就是说要敲单调队列喽。。。

既然要写moque,就要着重考虑一下啥时候该删除了。首先把窝萌的查询的框分成4部分:

 

假设窝萌的小正方形从左上角往下动,那么很显然1区域对于两个方向只是添加,2区域对于y方向是增加,对于x方向是维护,3区域对于x方向是增加,对于y方向是维护,4区域对于两个方向都是维护。

那就好办呀,对于不同的部分用不同的办法维护不就好了。。。。

注意这里有个细节:比如窝萌维护1区域的时候一定是1~n-1!!!为啥?因为i=n的时候就需要开始回答了!

然后说一下单调队列:窝萌还需要记录一下进队的时间,用来维护pop操作。然后就码就行了。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<stack>
 6 #include<queue>
 7 #include<cstring>
 8 #define PAU putchar(' ')
 9 #define ENT putchar('\n')
10 using namespace std;
11 const int maxn=1000+10,inf=-1u>>1;
12 struct moque{
13     int a1[1001],t1[1001],a2[1001],t2[1001];
14     int st1,ed1,st2,ed2;
15     moque(){st1=1;ed1=0;st2=1;ed2=0;}
16     void pushmi(int x,int t){
17         while((st1<=ed1)&&(x<=a1[ed1]))ed1--;ed1++;a1[ed1]=x;t1[ed1]=t;return;
18     }
19     void pushmx(int x,int t){
20         while((st2<=ed2)&&(x>=a2[ed2]))ed2--;ed2++;a2[ed2]=x;t2[ed2]=t;return;
21     }
22     void pop(int t){
23         if(t1[st1]==t)st1++;if(t2[st2]==t)st2++;return;
24     }
25     int qmin(){return a1[st1];}
26     int qmax(){return a2[st2];}
27 }qx[maxn],qy[maxn];
28 int a,b,n,A[maxn][maxn];
29 inline int read(){
30     int x=0,sig=1;char ch=getchar();
31     for(;!isdigit(ch);ch=getchar())if(ch=='-')sig=0;
32     for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';
33     return sig?x:-x;
34 }
35 inline void write(int x){
36     if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
37     int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;
38     for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
39 }
40 int main(){
41     a=read();b=read();n=read();
42     for(int i=1;i<=a;i++)for(int j=1;j<=b;j++)A[i][j]=read();
43     for(int i=1;i<n;i++){
44         for(int j=1;j<n;j++)qx[i].pushmi(A[i][j],j),qx[i].pushmx(A[i][j],j);
45         for(int j=n;j<=b;j++){
46             qx[i].pushmi(A[i][j],j);qx[i].pushmx(A[i][j],j);
47             qy[j].pushmi(qx[i].qmin(),i);qy[j].pushmx(qx[i].qmax(),i);
48             qx[i].pop(j-n+1);
49         }
50     }int ans=inf;
51     for(int i=n;i<=a;i++){
52         for(int j=1;j<n;j++)qx[i].pushmi(A[i][j],j),qx[i].pushmx(A[i][j],j);
53         for(int j=n;j<=b;j++){
54             qx[i].pushmi(A[i][j],j);qx[i].pushmx(A[i][j],j);
55             qy[j].pushmi(qx[i].qmin(),i);qy[j].pushmx(qx[i].qmax(),i);
56             ans=min(ans,qy[j].qmax()-qy[j].qmin());
57             qx[i].pop(j-n+1);qy[j].pop(i-n+1);
58         }
59     }write(ans);
60     return 0;
61 }

 

你可能感兴趣的:(BZOJ 1047 [HAOI2007]理想的正方形)