题意:
给一个矩阵,求一个面积最大的子矩阵,该子矩阵内部任意元素之差小于等于k
求有极差限制的最大面积子矩阵
解析:
考虑n^3的算法
遍历上边,遍历下边
遍历右边,维护最大区间范围
我们在这个范围存在一个单调性,如果l1>l2,(l2,r)不行,呢么(l1,r)肯定不行
所以我们用两个个单调队列维护区间最大和最小值
我们不断入队,如果(区间最大值-区间最小值)>k,呢么l就要增加之至符合区间极差小于k
在l增大的过程中,两个队列队首也同时发生变化,然后贪心求最大面积即可
移窗问题的区间限制条件是固定的大小k,而这里是要求区间极差小于k,本质上处理方式是相同的
这个过程是个尺取法
ac:
#include<bits/stdc++.h>
#define MAXN 505
using namespace std;
int aa[MAXN][MAXN];
int maxs[MAXN],mins[MAXN];
int queA[MAXN],queB[MAXN];
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&aa[i][j]);
int ans=1;
for(int i=1;i<=n;i++)
{
for(int k=1;k<=n;k++){
maxs[k]=0,mins[k]=1e9;
}
for(int j=i;j<=n;j++)
{
if((n-i+1)*n<ans)
break;
for(int k=1;k<=n;k++){
maxs[k]=max(maxs[k],aa[j][k]);
mins[k]=min(mins[k],aa[j][k]);
}
if((j-i+1)*n<ans)
continue;
int La=1,Ra=0;//保存区间最大值的单调队列
int Lb=1,Rb=0;//保存区间最小值的单调队列
int l=1;
for(int r=1;r<=n;r++){
while(La<=Ra&&maxs[queA[Ra]]<=maxs[r])Ra--;//压入maxs[r]
queA[++Ra]=r;
while(Lb<=Rb&&mins[queB[Rb]]>=mins[r])Rb--;//压入maxs[l]
queB[++Rb]=r;
while(l<=r&&maxs[queA[La]]-mins[queB[Lb]]>m)//如果(l,r)区间的极差>m,就缩小l,
{
l++;
while(queA[La]<l&&La<=Ra)La++;//去掉单调队列里的无效元素
while(queB[Lb]<l&&Lb<=Rb)Lb++;
}
ans=max(ans,(j-i+1)*(r-l+1));
}
}
}
printf("%d\n",ans);
}
return 0;
}