题面描述
思路
(一年出两道单调队列)
(小花坛不能在大矩阵的边上)
理解一下题意,冥冥之中看见求和,就会想到不管三七二十一先求前缀和。
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
qr(s[i][j]),s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
for(int i=C+1;i<n;i++)
for(int j=D+1;j<m;j++)
a[i][j]=s[i][j]-s[i-C][j]-s[i][j-D]+s[i-C][j-D];//小花坛
for(int i=A;i<=n;i++)
for(int j=B;j<=m;j++)
b[i][j]=s[i][j]-s[i-A][j]-s[i][j-B]+s[i-A][j-B];//大矩阵
那么现在只需要在每个大矩阵中,找到肥沃值最小的小花坛做差更新答案就行了。
关键怎么在一个 A ∗ B A*B A∗B的大矩阵中找到肥沃度最小 C ∗ D C*D C∗D的小花坛。
观察发现 a [ i ] [ j ] a[i][j] a[i][j]实际上是以(i,j)为右下角的小花坛的肥沃度总和。
实际上 b [ i ] [ j ] − min ( a [ i − A + 2 + C , i − 1 ] [ j − B + 2 + D , j − 1 ] ) b[i][j]-\min(a[i-A+2+C,i-1][j-B+2+D,j-1]) b[i][j]−min(a[i−A+2+C,i−1][j−B+2+D,j−1])
那么又回归到了理想正方形了。
先处理一下 a [ i ] [ j − B + 2 + D , j − 1 ] a[i][j-B+2+D,j-1] a[i][j−B+2+D,j−1],为了方便起见,可以用一个 p p p数组储存值。
同时改变一下下标,使
if(j>=B-1)p[i][j+1]=a[i][q[l]];
这样统计答案的时候可以直接、高效。
得出 p p p数组之后
p [ i ] [ j ] p[i][j] p[i][j]实际上是 min ( a [ i ] [ j − B + 2 + D , j − 1 ] ) \min (a[i][j-B+2+D,j-1]) min(a[i][j−B+2+D,j−1]),
类似地,求出 g g g数组
g [ i ] [ j ] g[i][j] g[i][j]实际上就是 min ( a [ i − A + C + 2 , i − 1 ] [ j − B + 2 + D , j − 1 ] ) \min(a[i-A+C+2,i-1][j-B+2+D,j-1]) min(a[i−A+C+2,i−1][j−B+2+D,j−1])
max A ≤ i ≤ n , B ≤ j ≤ m b [ i ] [ j ] − g [ i ] [ j ] \max\limits_{A\le i\le n,B\le j \le m}b[i][j]-g[i][j] A≤i≤n,B≤j≤mmaxb[i][j]−g[i][j]即为答案。
AC code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define gc getchar()
using namespace std;
const int N=1e3+10;
inline void qr(int &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(int x)
{
if(x<0)x=-x,putchar('-');
if(x/10)qw(x/10);
putchar(x%10+48);
}
int a[N][N],s[N][N],b[N][N],g[N][N],p[N][N];
int q[N],l,r;
int main()
{
int n,m,A,B,C,D;qr(n),qr(m),qr(A),qr(B),qr(C),qr(D);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
qr(s[i][j]),s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
for(int i=C+1;i<n;i++)
for(int j=D+1;j<m;j++)
a[i][j]=s[i][j]-s[i-C][j]-s[i][j-D]+s[i-C][j-D];
for(int i=A;i<=n;i++)
for(int j=B;j<=m;j++)
b[i][j]=s[i][j]-s[i-A][j]-s[i][j-B]+s[i-A][j-B];
for(int i=C+1;i<n;i++)
{
l=1;r=0;
for(int j=D+1;j<m;j++)
{
while(l<=r&&q[l]<j-B+D+2)++l;
while(l<=r&&a[i][j]<=a[i][q[r]])--r;
q[++r]=j;if(j>=B-1)p[i][j+1]=a[i][q[l]];
}
}
for(int j=B;j<=m;j++)
{
l=1;r=0;
for(int i=C+1;i<n;i++)
{
while(l<=r&&q[l]<i-A+C+2)++l;
while(l<=r&&p[i][j]<=p[q[r]][j])--r;
q[++r]=i;if(i>=A-1)g[i+1][j]=p[q[l]][j];
}
}
int ans=0;
for(int i=A;i<=n;i++)
for(int j=B;j<=m;j++)
ans=max(ans,b[i][j]-g[i][j]);
qw(ans);puts("");
return 0;
}