传送门
这个题很早以前就看到了,一直没做,来填个坑。
其实就是算两次单调队列,维护一下就好了。。。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
int x=0;char ch=' ';int f=1;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int a,b,n;
int v[1001][1001],mx[1001][1001],mn[1001][1001];
int ansmx[1001][1001],ansmn[1001][1001];
int q[1001],pos[1001],l,r,ans=0x3f3f3f3f;
int main(){
a=read();b=read();n=read();
for(int i=1;i<=a;++i)
for(int j=1;j<=b;++j)
v[i][j]=read();
for(int i=1;i<=a;++i){
l=1;r=0;
for(int j=1;j<=b;++j){
while(l<=r&&j-pos[l]>=n)l++;
while(l<=r&&v[i][j]>=q[r])r--;
q[++r]=v[i][j];pos[r]=j;
mx[i][j]=q[l];
}
l=1;r=0;
for(int j=1;j<=b;++j){
while(l<=r&&j-pos[l]>=n)l++;
while(l<=r&&v[i][j]<=q[r])r--;
q[++r]=v[i][j];pos[r]=j;
mn[i][j]=q[l];
}
}
for(int i=n;i<=b;++i){
l=1;r=0;
for(int j=1;j<=a;++j){
while(l<=r&&j-pos[l]>=n)l++;
while(l<=r&&mx[j][i]>=q[r])r--;
q[++r]=mx[j][i];pos[r]=j;
ansmx[j][i]=q[l];
}
l=1;r=0;
for(int j=1;j<=a;++j){
while(l<=r&&j-pos[l]>=n)l++;
while(l<=r&&mn[j][i]<=q[r])r--;
q[++r]=mn[j][i];pos[r]=j;
ansmn[j][i]=q[l];
}
}
for(int i=n;i<=a;i++){
for(int j=n;j<=b;j++){
ans=min(ans,ansmx[i][j]-ansmn[i][j]);
}
}
printf("%d\n",ans);
return 0;
}