[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
思路
观察样例之后,我们一个比较自然的思想就是,由于是要求最值,我们可以用优先队列先纵向操作来不断更新长度为k的队列,维护一个单调不增队列和一个单调不降队列,得到了两个(n-k)*(n-k)的矩阵,然后,再横向对得到的矩阵进行相似的处理即可,数组注意一定要开足够大(第一次90就跪在这儿了)!
单调队列用一个双端队列来维护。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<deque>
using namespace std;
int i,j,m,n,k;
int a[2001][2001];
int b[2001][2001];
int c[2001][2001];
int d[2001][2001];
int e[2001][2001];
int r()
{
int aans=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
aans*=10;
aans+=ch-'0';
ch=getchar();
}
return aans*f;
}
int main()
{
n=r(),m=r(),k=r();
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
a[i][j]=r();
}
for(i=1;i<=m;i++)
{
deque<int>q,p;
q.push_back(a[1][i]);
p.push_back(1);
for(j=2;j<=k;j++)
{
while(!q.empty()&&q.back()>a[j][i])
{q.pop_back();
p.pop_back();}
q.push_back(a[j][i]);
p.push_back(j);
}
b[1][i]=q.front();
for(j=k+1;j<=n;j++)
{
while(!q.empty()&&q.back()>a[j][i])
{q.pop_back();
p.pop_back();}
q.push_back(a[j][i]);
p.push_back(j);
while(p.front()<j-k+1)
{q.pop_front();
p.pop_front();}
b[j-k+1][i]=q.front();
}
}
for(i=1;i<=n;i++)
{
deque<int>q,p;
q.push_back(b[i][1]);
p.push_back(1);
for(j=2;j<=k;j++)
{
while(!q.empty()&&q.back()>b[i][j])
{q.pop_back();
p.pop_back();}
q.push_back(b[i][j]);
p.push_back(j);
}
d[i][1]=q.front();
for(j=k+1;j<=m;j++)
{
while(!q.empty()&&q.back()>b[i][j])
{q.pop_back();
p.pop_back();}
q.push_back(b[i][j]);
p.push_back(j);
while(p.front()<j-k+1)
{q.pop_front();
p.pop_front();}
d[i][j-k+1]=q.front();
}
}
for(i=1;i<=m;i++)
{
deque<int>q,p;
q.push_back(a[1][i]);
p.push_back(1);
for(j=2;j<=k;j++)
{
while(!q.empty()&&q.back()<a[j][i])
{q.pop_back();
p.pop_back();}
q.push_back(a[j][i]);
p.push_back(j);
}
c[1][i]=q.front();
for(j=k+1;j<=n;j++)
{
while(!q.empty()&&q.back()<a[j][i])
{q.pop_back();
p.pop_back();}
q.push_back(a[j][i]);
p.push_back(j);
while(p.front()<j-k+1)
{q.pop_front();
p.pop_front();}
c[j-k+1][i]=q.front();
}
}
for(i=1;i<=n;i++)
{
deque<int>q,p;
q.push_back(c[i][1]);
p.push_back(1);
for(j=2;j<=k;j++)
{
while(!q.empty()&&q.back()<c[i][j])
{q.pop_back();
p.pop_back();}
q.push_back(c[i][j]);
p.push_back(j);
}
e[i][1]=q.front();
for(j=k+1;j<=m;j++)
{
while(!q.empty()&&q.back()<c[i][j])
{q.pop_back();
p.pop_back();}
q.push_back(c[i][j]);
p.push_back(j);
while(p.front()<j-k+1)
{q.pop_front();
p.pop_front();}
e[i][j-k+1]=q.front();
}
}
int minn=1000000000;
for(i=1;i<=n-k+1;i++)
for(j=1;j<=m-k+1;j++)
{
if(minn>e[i][j]-d[i][j])
minn=e[i][j]-d[i][j];
}
cout<<minn;
}
/*
5 4 2
1 5 6 2
4 8 2 0
5 3 1 4
2 3 8 4
7 8 9 3
*/