Link:
Solution:
先对每个点算出以$(i,j)$为矩形右下角时的权值和
问题就转化为对于以$(i,j)$为右下角的$a*b$的矩形中的最小值
这时模型和 [BZOJ 1047]理想的正方形 就基本相同了,做两次单调队列就好了
Tip:
1、$c*d$处于$a*b$边界的情况不能选,注意边界判断
2、算矩阵和时是用$pre[i-a][j-b]$而不是$pre[i-a-1][j-b-1]$……
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=1005; int n,m,a,b,c,d,x,l,r,q[MAXN],res=0; int pre[MAXN][MAXN],mx[MAXN][MAXN],mn[MAXN][MAXN],ori[MAXN][MAXN]; int get1(int i,int j,int x) {return pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+x;} int get2(int i,int j,int l,int r) {return pre[i][j]+pre[i-l][j-r]-pre[i][j-r]-pre[i-l][j];} int main() { scanf("%d%d%d%d%d%d",&n,&m,&a,&b,&c,&d); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&x),pre[i][j]=get1(i,j,x); memset(mn,0x3f,sizeof(mn));memset(ori,0x3f,sizeof(ori)); for(int i=a;i<=n;i++) for(int j=b;j<=m;j++) mx[i][j]=get2(i,j,a,b); for(int i=c;i<=n;i++) for(int j=d;j<=m;j++) ori[i][j]=min(ori[i][j],get2(i,j,c,d)); for(int i=c;i<=n;i++) { l=1;r=0; for(int j=d;j<=m;j++) { while(l<=r&&j-q[l]>b-d-2) l++;//注意去掉边界情况 while(l<=r&&ori[i][j]<ori[i][q[r]]) r--; q[++r]=j;mn[i][j]=min(mn[i][j],ori[i][q[l]]); } } for(int j=d;j<=m;j++) { l=1;r=0; for(int i=c;i<=n;i++) { while(l<=r&&i-q[l]>a-c-2) l++; while(l<=r&&mn[i][j]<mn[q[r]][j]) r--; q[++r]=i; if(i+1>=a&&j+1>=b&&i+1<=n&&j+1<=m) res=max(res,mx[i+1][j+1]-mn[q[l]][j]); } } printf("%d",res); return 0; }