原来以为是什么神题。。。结果。。。我的三观。。。
大概是一道码农题,所有三种情况的分类如下
(图源Galaxies:http://www.cnblogs.com/galaxies/p/bzoj1177.html)
先前缀和乱搞,然后计算一个点的四个方位的k*k的正方形中的总贡献,左上右上左下右下分别为abcd,然后大力枚举讨论每种情况就好了。。。
(真是一道练习写数组下标的码农好题)
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2005;
int n,m,k,ans;
int a[maxn][maxn],b[maxn][maxn],c[maxn][maxn],d[maxn][maxn],map[maxn][maxn],s[maxn][maxn];
int main()
{
scanf("%d%d%d",&m,&n,&k);
for(int i=1;i<=m;i++)//二维前缀和
for(int j=1;j<=n;j++)
scanf("%d",&map[j][i]),
map[j][i]=map[j][i]+map[j][i-1]+map[j-1][i]-map[j-1][i-1];
for(int i=n;i>=k;i--)//计算(i,j)点左上角k*k矩形贡献
for(int j=m;j>=k;j--)
s[i][j]=map[i][j]-map[i][j-k]-map[i-k][j]+map[i-k][j-k];
//左上
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=max(s[i][j],max(a[i-1][j],a[i][j-1]));
//右上
for(int i=n;i;i--)
for(int j=1;j<=m;j++)
b[i][j]=max(s[i+k-1][j],max(b[i+1][j],b[i][j-1]));
//左下
for(int i=1;i<=n;i++)
for(int j=m;j;j--)
c[i][j]=max(s[i][j+k-1],max(c[i-1][j],c[i][j+1]));
//右下
for(int i=n;i;i--)
for(int j=m;j;j--)
d[i][j]=max(s[i+k-1][j+k-1],max(d[i+1][j],d[i][j+1]));
//两竖线
for(int i=k;i<=n-k*2;i++)
for(int j=k;j<=m;j++)
ans=max(ans,a[i][m]+s[i+k][j]+b[i+k+1][m]);
//两横线
for(int i=k;i<=m-k*2;i++)
for(int j=k;j<=m;j++)
ans=max(ans,b[1][i]+s[j][i+k]+c[n][i+k+1]);
//一竖线左边一横线
for(int i=k;i<=n-k;i++)
for(int j=k;j<=m-k;j++)
ans=max(ans,a[i][j]+c[i][j+1]+d[i+1][1]);
//一竖线右边一横线
for(int i=k;i<=n-k;i++)
for(int j=k;j<=m-k;j++)
ans=max(ans,a[i][m]+b[i+1][j]+d[i+1][j+1]);
//一横线上边一竖线
for(int i=k;i<=m-k;i++)
for(int j=k;j<=n-k;j++)
ans=max(ans,a[i][j]+b[i+1][j]+d[1][j+1]);
//一横线上边一竖线
for(int i=k;i<=m-k;i++)
for(int j=k;j<=n-k;j++)
ans=max(ans,b[i][1]+c[i+1][j]+d[i+1][j+1]);
cout<<ans;
return 0;
}