Description
有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。
Input
第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000
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
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
Sample Output
1
复杂度明显是N2的那就跑单调队列,先横着跑,再竖着跑。。
//MT_LI #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; int d[1100][1100]; int a,b,n; int mn[1100][1100],mx[1100][1100]; int minn[1100][1100],maxx[1100][1100]; struct line{ int x,pos; }list[510000];int head,tail; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void solve_max() { for(int i=1;i<=a;i++) { head=1,tail=0; for(int j=1;j<=n;j++) { while(head<=tail&&list[tail].x<d[i][j])tail--; list[++tail].x=d[i][j],list[tail].pos=j; } mx[i][1]=list[head].x; for(int j=n+1;j<=b;j++) { while(head<=tail&&list[head].pos<j-n+1)head++; while(head<=tail&&list[tail].x<d[i][j])tail--; list[++tail].x=d[i][j],list[tail].pos=j; mx[i][j-n+1]=list[head].x; } } for(int j=n+1;j<=b+1;j++) { head=1,tail=0; for(int i=1;i<=n;i++) { while(head<=tail&&list[tail].x<mx[i][j-n])tail--; list[++tail].x=mx[i][j-n],list[tail].pos=i; } maxx[1][j-n]=list[head].x; for(int i=n+1;i<=a;i++) { while(head<=tail&&list[head].pos<i-n+1)head++; while(head<=tail&&list[tail].x<mx[i][j-n])tail--; list[++tail].x=mx[i][j-n];list[tail].pos=i; maxx[i-n+1][j-n]=list[head].x; } } } void solve_min() { for(int i=1;i<=a;i++) { head=1,tail=0; for(int j=1;j<=n;j++) { while(head<=tail&&list[tail].x>d[i][j])tail--; list[++tail].x=d[i][j],list[tail].pos=j; } mn[i][1]=list[head].x; for(int j=n+1;j<=b;j++) { while(head<=tail&&list[head].pos<j-n+1)head++; while(head<=tail&&list[tail].x>d[i][j])tail--; list[++tail].x=d[i][j],list[tail].pos=j; mn[i][j-n+1]=list[head].x; } } for(int j=n+1;j<=b+1;j++) { head=1,tail=0; for(int i=1;i<=n;i++) { while(head<=tail&&list[tail].x>mn[i][j-n])tail--; list[++tail].x=mn[i][j-n],list[tail].pos=i; } minn[1][j-n]=list[head].x; for(int i=n+1;i<=a;i++) { while(head<=tail&&list[head].pos<i-n+1)head++; while(head<=tail&&list[tail].x>mn[i][j-n])tail--; list[++tail].x=mn[i][j-n];list[tail].pos=i; minn[i-n+1][j-n]=list[head].x; } } } int main() { scanf("%d%d%d",&a,&b,&n); for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) d[i][j]=read(); solve_max();solve_min(); int ans=1<<30; for(int i=1;i<=a-n+1;i++) for(int j=1;j<=b-n+1;j++) ans=min(ans,maxx[i][j]-minn[i][j]); printf("%d\n",ans); return 0; }