欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1177
题意概括
在一个n*m的矩阵中,每一个位置一个数字。
现在让你选出3个k*k的矩阵,它们互不相交,问最大数值和为多少。
注意:n,m<=1500
题解
一开始总想着dp,发现不大可能。
暴搜也不行。
然后突然发现,很简单,情况总数非常的少。
只有以下6种,从3个区域中各选择一个最大的。
然后就很简单了,我们只需要预处理矩阵前缀和,左上左下右上右下4个方向的前缀max。
然后对于前两种,分别枚举一下列号和行号;
对于后四种,只要枚举中间点就可以了。
所以复杂度为n2。可以过去了。
代码
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=1500+5;
int n,m,k,nn,mm;
int a[N][N],sum[N][N],val[N][N],Row[N],Col[N],LU[N][N],RU[N][N],LD[N][N],RD[N][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",&a[i][j]);
memset(sum,0,sizeof sum);
memset(val,0,sizeof val);
memset(Row,0,sizeof Row);
memset(Col,0,sizeof Col);
memset(LU,0,sizeof LU);
memset(RU,0,sizeof RU);
memset(LD,0,sizeof LD);
memset(RD,0,sizeof RD);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
nn=n-k+1,mm=m-k+1;
for (int i=1;i<=nn;i++)
for (int j=1;j<=mm;j++)
val[i][j]=sum[i+k-1][j+k-1]-sum[i-1][j+k-1]-sum[i+k-1][j-1]+sum[i-1][j-1];
for (int i=1;i<=nn;i++)
for (int j=1;j<=mm;j++)
Row[i]=max(Row[i],val[i][j]),Col[j]=max(Col[j],val[i][j]);
for (int i=1;i<=nn;i++)
for (int j=1;j<=mm;j++)
LU[i][j]=max(val[i][j],max(LU[i-1][j],LU[i][j-1]));
for (int i=1;i<=nn;i++)
for (int j=mm;j>=1;j--)
RU[i][j]=max(val[i][j],max(RU[i-1][j],RU[i][j+1]));
for (int i=nn;i>=1;i--)
for (int j=1;j<=mm;j++)
LD[i][j]=max(val[i][j],max(LD[i+1][j],LD[i][j-1]));
for (int i=nn;i>=1;i--)
for (int j=mm;j>=1;j--)
RD[i][j]=max(val[i][j],max(RD[i+1][j],RD[i][j+1]));
int ans=0;
/*---- ---- ----- ----- ----- -----
|||| |--| | | | |---| | |-| |-| |
---- |--| ----- | | | ----- -----
---- |---| ----- */
for (int i=1;i<=nn;i++){
int Max=0;
for (int j=i+k;j<=nn;j++){
Max=max(Max,Row[j]);
if (j+k>nn)
break;
ans=max(ans,LU[i][mm]+Max+LD[j+k][mm]);
}
}
for (int i=1;i<=mm;i++){
int Max=0;
for (int j=i+k;j<=mm;j++){
Max=max(Max,Col[j]);
if (j+k>mm)
break;
ans=max(ans,LU[nn][i]+Max+RU[nn][j+k]);
}
}
for (int i=k+1;i<=nn;i++)
for (int j=k+1;j<=mm;j++){
int lu=LU[i-k][j-k],ru=RU[i-k][j],ld=LD[i][j-k],rd=RD[i][j];
ans=max(ans,lu+ru+LD[i][mm]);
ans=max(ans,lu+ld+RU[nn][j]);
ans=max(ans,ld+rd+LU[i-k][mm]);
ans=max(ans,rd+ru+LU[nn][j-k]);
}
printf("%d",ans);
return 0;
}