[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

先求出每列往前n个的最小值和最大值,然后在用这个东西求出二维的往前上方n*n的正方形的最大值和最小值.
可以用一个set实时维护插入和删除,复杂度O(n^2log(n)).
更优的做法:用两个单调队列维护,每次队首都是最大值或最小值,实时维护插入和删除,插入是从后面开始比他大或小的都删掉,维护单调性,因为每个点只会出入队一次,复杂度O(n^2).

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<string>
 6 #include<algorithm>
 7 #include<map>
 8 #include<complex>
 9 #include<queue>
10 #include<stack>
11 #include<cmath>
12 #include<set>
13 #include<vector>
14 #define maxn 1100
15 #define IT multiset<int>::iterator
16 using namespace std;
17 int mp[maxn][maxn],zx[maxn][maxn],zd[maxn][maxn],zx1[maxn][maxn],zd1[maxn][maxn];
18 struct data{
19   int head,tail,q[maxn],p[maxn];
20   void clear(){head=1,tail=0;}
21   void push1(int key,int id){
22     while(head<=tail && q[tail]>key)tail--;
23     q[++tail]=key,p[tail]=id;
24   }
25   void push2(int key,int id){
26     while(head<=tail && q[tail]<key)tail--;
27     q[++tail]=key,p[tail]=id;
28   }
29   void pop(int id){
30     while(p[head]<=id && head<=tail) head++;
31   }
32   int front(){
33     return q[head];
34   }
35 }q1,q2;
36 int main(){
37   int n,m,k;
38   scanf("%d%d%d",&n,&m,&k);
39   for(int i=1;i<=n;i++)
40     for(int j=1;j<=m;j++)
41       scanf("%d",&mp[i][j]);
42   for(int i=1;i<=n;i++){
43     q1.clear();
44     q2.clear();
45     for(int j=1;j<=k;j++)
46       q1.push1(mp[i][j],j),q2.push2(mp[i][j],j);
47     zx1[i][k]=q1.front();zd1[i][k]=q2.front();
48     for(int j=k+1;j<=m;j++){
49       q1.pop(j-k),q2.pop(j-k);
50       q1.push1(mp[i][j],j);q2.push2(mp[i][j],j);
51       zx1[i][j]=q1.front();zd1[i][j]=q2.front();
52     }
53   }
54   for(int j=k;j<=m;j++){
55     q1.clear();
56     for(int i=1;i<=k;i++)
57       q1.push1(zx1[i][j],i);
58     zx[k][j]=q1.front();
59     for(int i=k+1;i<=n;i++){
60       q1.pop(i-k);
61       q1.push1(zx1[i][j],i);
62       zx[i][j]=q1.front();
63     }
64   }
65   for(int j=k;j<=m;j++){
66     q2.clear();
67     for(int i=1;i<=k;i++)
68       q2.push2(zd1[i][j],i);
69     zd[k][j]=q2.front();
70     for(int i=k+1;i<=n;i++){
71       q2.pop(i-k);
72       q2.push2(zd1[i][j],i);
73       zd[i][j]=q2.front();
74     }
75   }
76   int ans=2000000000;
77   for(int i=k;i<=n;i++)
78     for(int j=k;j<=m;j++)
79       ans=min(ans,zd[i][j]-zx[i][j]);
80   printf("%d",ans);
81   return 0;
82 }

 

posted @ 2017-09-10 22:37  嘘丶  阅读(184)  评论(0编辑  收藏  举报