洛谷P2216 [HAOI2007] 理想的正方形

 

题目描述

有一个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

 

跑两遍DP,第一遍处理出行i内以j为端点的长度为n的区间内的最大值和最小值。

第二遍DP,根据之前处理出的一维区间最值,DP出二维区间最值。

然后枚举区间端点,找最优解。

需要用单调队列优化

 

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 using namespace std;
 9 const int mxn=1010;
10 int read(){
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 int mp[mxn][mxn];
17 int fmx[mxn][mxn],fmi[mxn][mxn];
18 int dpmx[mxn][mxn],dpmi[mxn][mxn];
19 int a,b,n;
20 void work(){
21     
22 }
23 int q1[mxn],hd1=0,tl1=0;
24 int q2[mxn],hd2=0,tl2=0;
25 int main(){
26     a=read();b=read();n=read();
27     int i,j;
28     memset(fmi,0x3f,sizeof fmi);
29     for(i=1;i<=a;i++){
30         hd1=hd2=1;
31         tl1=tl2=0;
32         for(j=1;j<=b;j++){
33             mp[i][j]=read();
34             while(hd1<=tl1 && j-q1[hd1]>=n)hd1++;
35             while(hd1<=tl1 && mp[i][j]>=mp[i][q1[tl1]]) tl1--;
36             q1[++tl1]=j;
37             fmx[i][j]=mp[i][q1[hd1]];
38             //max
39             while(hd2<=tl2 && j-q2[hd2]>=n)hd2++;
40             while(hd2<=tl2 && mp[i][j]<=mp[i][q2[tl2]]) tl2--;
41             q2[++tl2]=j;
42             fmi[i][j]=mp[i][q2[hd2]];
43             //min
44         }
45     }
46     memset(dpmi,0x3f,sizeof dpmi);
47     hd1=hd2=1;tl1=tl2=0;
48     for(j=1;j<=b;j++){
49         hd1=hd2=1;tl1=tl2=0;
50         for(i=1;i<=a;i++){
51             while(hd1<=tl1 && i-q1[hd1]>=n)hd1++;
52             while(hd1<=tl1 && fmx[i][j]>=fmx[q1[tl1]][j])tl1--;
53             q1[++tl1]=i;
54             dpmx[i][j]=fmx[q1[hd1]][j];
55             
56             while(hd2<=tl2 && i-q2[hd2]>=n)hd2++;
57             while(hd2<=tl2 && fmi[i][j]<=fmi[q2[tl2]][j])tl2--;
58             q2[++tl2]=i;
59             dpmi[i][j]=fmi[q2[hd2]][j];
60             
61         }
62     }
63     int ans=0x3f3f3f3f;
64     for(i=n;i<=a;i++)
65      for(j=n;j<=b;j++){
66          ans=min(ans,dpmx[i][j]-dpmi[i][j]);
67      }
68     printf("%d\n",ans);
69     return 0;
70 }

 

posted @ 2016-10-20 20:26  SilverNebula  阅读(277)  评论(0编辑  收藏  举报
AmazingCounters.com