BZOJ1047: [HAOI2007]理想的正方形
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
题解Here!
一看题——这绝对是$DP$!
然后这个$flag$在$3s$之后被推翻了。
数据范围$n,m<=10^3,q<=10^2$。。。
那就直接单调队列维护每行每列,然后暴力求出最小值就好了啊!
单调队列是啥不用多说。
设$f[i][j]$表示第$i$行中$[j,j+q-1]$之间的最大值,$g[i][j]$表示第$i$行中$[j,j+q-1]$之间的最小值。
显然直接维护就好。
然后再套一个单调队列:
设$maxn[i][j]$表示$f[i][j]$中$[i,i+q-1]$行的第$j$列的最大值,$maxn[i][j]$表示$g[i][j]$中$[i,i+q-1]$行的第$j$列的最小值。
显然可以同上,直接单调队列维护就好。
然后暴力求出$maxn[i][j]-minn[i][j]$的最小值。
至于单调队列怎么实现。。。
我偷个懒,直接用$STL$——$deque$,双端队列。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<deque> #define MAXN 1010 using namespace std; deque<int> que_max,que_min; int n,m,q,ans=2147483646; int val[MAXN][MAXN],f[MAXN][MAXN],g[MAXN][MAXN],maxn[MAXN][MAXN],minn[MAXN][MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } void work(){ for(int j=1;j<=m-q+1;j++){ que_max.clear();que_min.clear(); que_max.push_back(1);que_min.push_back(1); for(int i=2;i<=n;i++){ while(!que_max.empty()&&f[i][j]>=f[que_max.back()][j])que_max.pop_back(); while(!que_min.empty()&&g[i][j]<=g[que_min.back()][j])que_min.pop_back(); que_max.push_back(i); que_min.push_back(i); while(i-que_max.front()>=q)que_max.pop_front(); while(i-que_min.front()>=q)que_min.pop_front(); if(i>=q){ maxn[i-q+1][j]=f[que_max.front()][j]; minn[i-q+1][j]=g[que_min.front()][j]; } } } for(int i=1;i<=n-q+1;i++) for(int j=1;j<=m-q+1;j++) ans=min(ans,maxn[i][j]-minn[i][j]); printf("%d\n",ans); } void init(){ n=read();m=read();q=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) val[i][j]=read(); for(int i=1;i<=n;i++){ que_max.clear();que_min.clear(); que_max.push_back(1);que_min.push_back(1); for(int j=2;j<=m;j++){ while(!que_max.empty()&&val[i][j]>=val[i][que_max.back()])que_max.pop_back(); while(!que_min.empty()&&val[i][j]<=val[i][que_min.back()])que_min.pop_back(); que_max.push_back(j); que_min.push_back(j); while(j-que_max.front()>=q)que_max.pop_front(); while(j-que_min.front()>=q)que_min.pop_front(); if(j>=q){ f[i][j-q+1]=val[i][que_max.front()]; g[i][j-q+1]=val[i][que_min.front()]; } } } } int main(){ init(); work(); return 0; }