啧……明明以前做到过这种类型的题结果全忘了……
这种矩阵的,一般都是先枚举行,然后对列进行一遍单调队列,搞出右下角在每一行中合法位置时的最小权值
再枚举列,对行做一遍单调队列,用之前搞出来的最小权值再做一次单调队列,更新答案
感觉很难讲清楚啊……看代码好了……虽然代码可能更不清楚……
1 //minamoto 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 5 char buf[1<<21],*p1=buf,*p2=buf; 6 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 8 inline int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 const int N=1005; 19 int sum[N][N],sum1[N][N],sum2[N][N],q[N],mn[N][N]; 20 int n,m,A,B,C,D,h,t,res; 21 void init(){ 22 for(int i=C+1;i<n;++i){ 23 h=1,t=0; 24 for(int j=D+1;j<m;++j){ 25 while(h<=t&&sum2[i][q[t]]>=sum2[i][j]) --t; 26 q[++t]=j; 27 if(q[h]<=j-B+D+1) ++h; 28 mn[i][j]=sum2[i][q[h]]; 29 } 30 } 31 } 32 void solve(){ 33 for(int j=D+1;j<m;++j){ 34 h=1,t=0; 35 for(int i=C+1;i<n;++i){ 36 while(h<=t&&mn[q[t]][j]>=mn[i][j]) --t; 37 q[++t]=i; 38 if(q[h]<=i-A+C+1) ++h; 39 cmax(res,sum1[i+1][j+1]-mn[q[h]][j]); 40 } 41 } 42 } 43 int main(){ 44 // freopen("testdata.in","r",stdin); 45 n=read(),m=read(),A=read(),B=read(),C=read(),D=read(); 46 if(n==2||m==2) return puts("0"),0; 47 for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) 48 sum[i][j]=read()+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; 49 for(int i=A;i<=n;++i) for(int j=B;j<=m;++j) 50 sum1[i][j]=sum[i][j]-sum[i-A][j]-sum[i][j-B]+sum[i-A][j-B]; 51 for(int i=C;i<=n;++i) for(int j=D;j<=m;++j) 52 sum2[i][j]=sum[i][j]-sum[i-C][j]-sum[i][j-D]+sum[i-C][j-D]; 53 init(),solve(); 54 printf("%d ",res); 55 return 0; 56 }