[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 }