bzoj 1047 理想的正方形
题目大意:
有一个a*b的矩阵,求所有矩阵内n*n的子矩阵内最大值与最小值之差的最小值
思路:
根据可以看出这是一道裸的单调队列。
具体来说,就是用单调队列先维护出每行每个点左侧n个点以内的最大值,记为 t 数组。外层循环为a,内层为b
然后再用单调队列维护每个点上方n个点以内的 t 数组的最大值,这样通过单调队列就能求出以每个点为右下角的子矩阵的最大值
然后求每个点为右下角的子矩阵的最小值,方法同上
就是这样
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<queue> #include<vector> #include<set> #include<stack> #define inf 2147483611 #define ll long long #define MAXN 1010 using namespace std; inline int read() { int x=0,f=1; char ch;ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } int n,a,b,head,tail; struct data { int pos,val; }q[MAXN]; int map[MAXN][MAXN],t[MAXN][MAXN],maxa[MAXN][MAXN],mina[MAXN][MAXN]; int main() { a=read(),b=read(),n=read(); for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) map[i][j]=read(); for(int i=1;i<=a;i++) { head=1,tail=0; for(int j=1;j<=b;j++) { while(head<=tail&&q[tail].val<=map[i][j]) tail--; while(head<=tail&&q[head].pos<=j-n) head++; q[++tail].val=map[i][j],q[tail].pos=j; t[i][j]=q[head].val; } } for(int j=1;j<=b;j++) { head=1,tail=0; for(int i=1;i<=a;i++) { while(head<=tail&&q[tail].val<=t[i][j]) tail--; while(head<=tail&&q[head].pos<=i-n) head++; q[++tail].val=t[i][j],q[tail].pos=i; maxa[i][j]=q[head].val; } } for(int i=1;i<=a;i++) { head=1,tail=0; for(int j=1;j<=b;j++) { while(head<=tail&&q[tail].val>=map[i][j]) tail--; while(head<=tail&&q[head].pos<=j-n) head++; q[++tail].val=map[i][j],q[tail].pos=j; t[i][j]=q[head].val; } } for(int j=1;j<=b;j++) { head=1,tail=0; for(int i=1;i<=a;i++) { while(head<=tail&&q[tail].val>=t[i][j]) tail--; while(head<=tail&&q[head].pos<=i-n) head++; q[++tail].val=t[i][j],q[tail].pos=i; mina[i][j]=q[head].val; } } int ans=inf; for(int i=n;i<=a;i++) for(int j=n;j<=b;j++) ans=min(ans,maxa[i][j]-mina[i][j]); printf("%d",ans); }