思路

先写两重循环枚举起点行k1到终点行k2,再写一个循环遍历每列i,将列i压缩成一个数字,它表示第i列k1~k2行的前缀和(用二维前缀和预处理),那么就变成了一个1*n的矩阵,即一个一维数组,然后求其最大子段和,同时取max即可。

时间复杂度O(n^3)。

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=510,inf=1e18;
typedef long long ll;
ll a[N][N],sum[N][N],dp[N];
int main()
{
    ios::sync_with_stdio(false);
    int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>a[i][j];
            sum[i][j]=sum[i-1][j]+a[i][j]; // 第j列前i行的前缀和
        }
    }
    ll mx=-inf;
    for(int k1=1;k1<=n;k1++) // 行 上端点
    {
        for(int k2=k1;k2<=n;k2++) // 行 下端点
        {
            //dp[0]=0;
            for(int i=1;i<=n;i++) // 列
            {
                ll tmp=sum[k2][i]-sum[k1-1][i]; // 第i列 [k1,k2]行之和
                dp[i]=max(dp[i-1]+tmp,tmp); // 最大子段和求法
                mx=max(mx,dp[i]);
            }
        }
    }
    printf("%lld\n",mx);
    return 0;
}
/*
3
-1 -4 3
3 4 -1
-5 -2 8
ans:10

4
0 -2 -7 0
9 2 -6 2
-4 1 -4  1
-1 8  0 -2
ans:15
*/