题目链接:https://codeforces.com/problemset/problem/173/C
题目大意:
对一个边长k为奇数的正方形,有一条螺旋线(黑色)。
现在给你一个长宽分别为n, m的矩阵。问你子正方形的螺旋线和的最大值。
思路:我们枚举每一个子正方形。有O(n^3)个,如果我们能够在O(1)求出每一个子正方形的螺旋线和,就可以了。
我们观察对一个正方形。
内部是一个小的子正方形。而白色部分就是子正方形的螺旋线的和。
那么我们用f[i][j][k]:在(i, j)边长为k的正方形螺旋线的和。如果我们最先枚举k就可以进行滚动数组优化。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
int a[505][505];
int sum[505][505];
int f[505][505][2];
int S(int x, int y, int i, int j){
return sum[i][j]-sum[i][y-1]-sum[x-1][j]+sum[x-1][y-1];
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
scanf("%d", &a[i][j]);
f[i][j][0]=a[i][j];
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
}
int ans=-1<<30;
for(int len=3; len<=min(n, m); len+=2){
for(int i=1; i<=n; i++){
if(i+len-1>n) continue;
for(int j=1; j<=m; j++){
if(j+len-1>m) continue;
f[i][j][1]=S(i, j, i+len-1, j+len-1);
f[i][j][1]-=f[i+1][j+1][0];
f[i][j][1]-=a[i+1][j];
ans=max(ans, f[i][j][1]);
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
f[i][j][0]=f[i][j][1];
}
}
}
printf("%d\n", ans);
return 0;
}