DP
其实主要是单调队列..
数据最大为一千,考虑O(n^2)的做法
在a*b的矩形中找出n^n的正方形再怎么样至少也要把a和b分别枚举吧。
必须考虑O(1)处理单个正方形最大最小值。
容易发现正方形大小不变为n,如果只看一行,就是滑动窗口,那么处理单个正方形最大最小值时间复杂度为O(n);
仔细思考后(没错不管是什么题目仔细思考后就一定能想出正解..)发现如果把单调队列更新的值存起来为mxa[i][j],mxa[i][j]表示第i行以第j列为结尾的数列的最大值.
则要求mxb[i][j](mxb[i][j]表示以i,j为右下角的正方形的最大值)就只要对mxa竖着跑b遍单调队列就好了..
正解出来了,但要注意i,j,的范围..
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int n,m,k; int a[1007][1007]; int posx[1007],posi[1007]; int mxa[1007][1007],mia[1007][1007]; int mxb[1007][1007],mib[1007][1007]; int main() { cin>>n>>m>>k; for(int i=1;i<=n;i++) { int heax=1,lasx=0,heai=1,lasi=0; for(int j=1;j<=m;j++) { scanf("%d",&a[i][j]); while(heax<=lasx&&a[i][j]>=a[i][posx[lasx]]) lasx--; while(heai<=lasi&&a[i][j]<=a[i][posi[lasi]]) lasi--; while(heax<=lasx&&j-posx[heax]>=k) heax++; while(heai<=lasi&&j-posi[heai]>=k) heai++; posx[++lasx]=j; posi[++lasi]=j; if(j>=k) mxa[i][j-k+1]=a[i][posx[heax]],mia[i][j-k+1]=a[i][posi[heai]]; } } memset(posx,0,sizeof(posx)); memset(posi,0,sizeof(posi)); for(int j=1;j<=m-k+1;j++) { int heax=1,lasx=0,heai=1,lasi=0; for(int i=1;i<=n;i++) { while(heax<=lasx&&mxa[i][j]>=mxa[posx[lasx]][j]) lasx--; while(heai<=lasi&&mia[i][j]<=mia[posi[lasi]][j]) lasi--; while(heax<=lasx&&i-posx[heax]>=k) heax++; while(heai<=lasi&&i-posi[heai]>=k) heai++; posx[++lasx]=i; posi[++lasi]=i; if(i>=k) mxb[i-k+1][j]=mxa[posx[heax]][j],mib[i-k+1][j]=mia[posi[heai]][j]; } } int ans=2147483647; for(int i=1;i<=n-k+1;i++) for(int j=1;j<=m-k+1;j++) ans=min(ans,mxb[i][j]-mib[i][j]); cout<<ans; return 0; }