背景:
第
200
200
200篇原创的文章,第
2100
2100
2100积分。
题目传送门:
https://www.luogu.org/problemnew/show/P2219
题意:
在一块
n
∗
m
n*m
n∗m的矩形中选择一块
x
1
∗
y
2
x1*y2
x1∗y2的矩阵,再从这个
x
1
∗
y
1
x1*y1
x1∗y1的矩阵中选择一块
x
2
∗
y
2
x2*y2
x2∗y2的矩阵,使得这两个矩阵的和的差最大。
思路:
设
f
i
,
j
f_{i,j}
fi,j以
(
i
,
j
)
(i,j)
(i,j)为右下角的矩阵的和。
则
f
i
,
j
=
f
i
−
1
,
j
+
f
i
,
j
−
1
−
f
i
−
1
,
j
−
1
f_{i,j}=f_{i-1,j}+f_{i,j-1}-f_{i-1,j-1}
fi,j=fi−1,j+fi,j−1−fi−1,j−1。
设
s
u
m
i
,
j
sum_{i,j}
sumi,j表示以
(
i
,
j
)
(i,j)
(i,j)为右下角的
x
2
∗
y
2
x2*y2
x2∗y2的矩阵的和。
则
s
u
m
i
,
j
=
f
i
,
j
−
f
i
−
x
2
+
1
−
1
,
j
−
f
i
,
j
−
y
2
+
1
−
1
+
f
i
−
x
2
+
1
−
1
,
j
−
y
2
+
1
−
1
sum_{i,j}=f_{i,j}-f_{i-x2+1-1,j}-f_{i,j-y2+1-1}+f_{i-x2+1-1,j-y2+1-1}
sumi,j=fi,j−fi−x2+1−1,j−fi,j−y2+1−1+fi−x2+1−1,j−y2+1−1。
注意:此时左上角还未确定,因此不可以统计答案。
用单调队列维护
s
u
m
sum
sum的最小值即可,类似于[HAOI2007]理想的正方形。
最后统计答案即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,x1,y1,x2,y2,ans=0;
int f[1010][1010],sum[1010][1010],mi[1010][1010],tot[1010][1010];
int que[1010];
void work1()
{
for(int i=x2;i<=n;i++)
{
int head=1,tail=0;
for(int j=y2;j<=m;j++)
{
while(head<=tail&&sum[i][que[tail]]>sum[i][j]) tail--;
mi[i][j]=sum[i][que[head]];
while(head<=tail&&j-que[head]+1>=y1-y2) head++;
que[++tail]=j;
}
}
}
void work2()
{
for(int j=y2;j<=m;j++)
{
int head=1,tail=0;
for(int i=x2;i<=n;i++)
{
while(head<=tail&&mi[que[tail]][j]>mi[i][j]) tail--;
tot[i][j]=mi[que[head]][j];
while(head<=tail&&i-que[head]+1>=x1-x2) head++;
que[++tail]=i;
}
}
}
int main()
{
int d;
scanf("%d %d %d %d %d %d",&n,&m,&x1,&y1,&x2,&y2);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&d);
f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+d;
if(i>=x2&&j>=y2) sum[i][j]=f[i][j]-f[i-x2+1-1][j]-f[i][j-y2+1-1]+f[i-x2+1-1][j-y2+1-1];
}
work1();
work2();
for(int i=x1;i<=n;i++)
for(int j=y1;j<=m;j++)
ans=max(ans,f[i][j]-f[i-x1+1-1][j]-f[i][j-y1+1-1]+f[i-x1+1-1][j-y1+1-1]-tot[i][j]);
printf("%d",ans);
}