题目描述
传送门
题解
将矩阵分割成3部分,分割一下其实可以发现,最多只有6中分割情况
对于每个位置维护以(x,y)为正方形的左上角,左下角,右上角,右下角,所得到的正方形的和。
然后在维护到每个位置的左前缀,右前缀,左后缀,右后缀的最大值。
暴力每种分割的方法计算答案。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 1503
using namespace std;
int n,m,k;
int tr[N][N],sum[N][N],a[N][N],b[N][N],c[N][N],d[N][N],h[N],l[N];
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) {
scanf("%d",&sum[i][j]);
sum[i][j]+=(sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]);
}
for (int i=k;i<=n;i++)
for (int j=k;j<=m;j++) {
tr[i][j]=sum[i][j]-sum[i-k][j]-sum[i][j-k]+sum[i-k][j-k];
h[i]=max(h[i],tr[i][j]);
l[j]=max(l[j],tr[i][j]);
}
for (int i=k;i<=n;i++)//(i,j)为矩形的右下角
for (int j=k;j<=m;j++)
a[i][j]=max(a[i-1][j],a[i][j-1]),
a[i][j]=max(tr[i][j],a[i][j]);
for (int i=k;i<=n;i++)//(i,j)为矩形的左下角
for (int j=m-k+1;j>=1;j--)
b[i][j]=max(b[i-1][j],b[i][j+1]),
b[i][j]=max(b[i][j],tr[i][j+k-1]);
for (int i=n-k+1;i>=1;i--)//(i,j)为矩形的左下角
for (int j=k;j<=m;j++)
c[i][j]=max(c[i+1][j],c[i][j-1]),
c[i][j]=max(c[i][j],tr[i+k-1][j]);
for (int i=n-k+1;i>=1;i--)//(i,j)为矩形的左上角
for (int j=m-k+1;j>=1;j--)
d[i][j]=max(d[i+1][j],d[i][j+1]),
d[i][j]=max(d[i][j],tr[i+k-1][j+k-1]);
int ans=0;
for (int i=k;i<=n-k;i++)
for (int j=k;j<=m-k;j++){
int t1=a[i][m]+c[i+1][j]+d[i+1][j+1];
int t2=c[i+1][m]+a[i][j]+b[i][j+1];
int t3=c[1][j]+b[i][j+1]+d[i+1][j+1];
int t4=a[i][j]+c[i+1][j]+d[1][j+1];
ans=max(ans,t1);
ans=max(ans,t2);
ans=max(ans,t3);
ans=max(ans,t4);
}
for (int i=k;i<=n-2*k;i++)
for (int j=i+k;j<=m-k;j++)
ans=max(ans,b[i][1]+h[j]+d[j+1][1]);
for (int i=k;i<=m-2*k;i++)
for (int j=i+k;j<=m-k;j++)
ans=max(ans,a[n][i]+l[j]+d[1][j+1]);
printf("%d\n",ans);
}