题目背景
题目并没有什么含义,只是想宣传一下自己的博客,Acheing.com
题目描述
给你一个n*m的矩阵,请你求出其中边长为k的子矩形,使得这个矩形中最大值减最小值最小。
输入输出格式
输入格式:n,m,k 接下来一个n*m的子矩阵.
输出格式:一个数,即最小值.
输入输出样例
输入样例#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<=n,m<=1000
1<=k<=min(n,m)
//单调队列运用 解决二维线段树超时的问题 #include<cstdio> #include<algorithm> using namespace std; inline int read(){ register int x=0;bool f=1; register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1010; int n,m,w,ans=0x7fffffff; int a[N][N]; int qmax[N],qmin[N],tmax,tmin,wmax,wmin; int maxx[N][N],minn[N][N]; int main(){ n=read();m=read();w=read(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ a[i][j]=read(); } } for(int j=1;j<=m;j++){ tmax=tmin=1; wmax=wmin=0; for(int i=1;i<=n;i++){ if(i-qmax[tmax]+1>w) tmax++; for(;tmax<=wmax&&a[i][j]>=a[qmax[wmax]][j];wmax--); qmax[++wmax]=i; if(i-qmin[tmin]+1>w) tmin++; for(;tmin<=wmin&&a[i][j]<=a[qmin[wmin]][j];wmin--); qmin[++wmin]=i; if(i>=w) maxx[i][j]=a[qmax[tmax]][j],minn[i][j]=a[qmin[tmin]][j]; } } for(int i=w;i<=n;i++){ tmax=tmin=1; wmax=wmin=0; for(int j=1;j<=m;j++){ if(j-qmax[tmax]+1>w) tmax++; for(;tmax<=wmax&&maxx[i][j]>=maxx[i][qmax[wmax]];wmax--); qmax[++wmax]=j; if(j-qmin[tmin]+1>w) tmin++; for(;tmin<=wmin&&minn[i][j]<=minn[i][qmin[wmin]];wmin--); qmin[++wmin]=j; if(j>=w) ans=min(ans,maxx[i][qmax[tmax]]-minn[i][qmin[tmin]]); } } printf("%d",ans); return 0; }