最大子矩阵和 $ n^3 $ 算法
$ solution: $
首先我们不难想到枚举上下左右边界,然后两层循环统计权值和,复杂度 $ O(n^6) $ 。这个我们用前缀和可以省去后面的循环,将复杂度降成 $ O(n^4) $ 。然后我们考虑不枚举上下左右四个边界,我们只枚举其中的上边界和下边界,于是题目转化成一个一维找权值最大区间。
于是我们考虑一个问题:怎样求一个数列的最大子段和。这个用DP可以做,设 $ f[i] $ 表示以 $ i $ 为右端点的最大字段和, $ f[i]=max(f[i-1]+a[i],a[i]) $ 这个我们可以 $ O(n) $ 计算。
于是我们求出这整个矩阵的向上的前缀和 $ s[i][j]=a[i][j]+s[i-1][j] $ ,这个可以 $ O(1) $ 求出上述一维状态下的权值。
总复杂度 $ O(n^3) $
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>#define ll long long
#define db double
#define rg register intusing namespace std;int n,ans;
int s[105][105];
int a[105],f[105];inline int qr(){register char ch; register bool sign=0; rg res=0;while(!isdigit(ch=getchar()))if(ch=='-')sign=1;while(isdigit(ch))res=res*10+(ch^48),ch=getchar();if(sign)return -res; else return res;
}int main(){//freopen(".in","r",stdin);//freopen(".out","w",stdout);n=qr(); f[0]=-1e9; ans=-1e9;for(rg i=1;i<=n;++i)for(rg j=1;j<=n;++j)s[i][j]=s[i-1][j]+qr();for(rg i=0;i<n;++i)for(rg j=i+1;j<=n;++j)for(rg k=1;k<=n;++k){a[k]=s[j][k]-s[i][k];f[k]=max(f[k-1]+a[k],a[k]);ans=max(ans,f[k]);}printf("%d\n",ans);return 0;
}