分享一道题
题目描述
给定一个 n 行 m 列的整数矩阵,找到一个非空子矩阵,使得该子矩阵的和的值最大。子矩阵是指由原矩 阵的连续若干行和连续若干列组成的矩阵。
输入格式
第一行包含两个整数 n 和 m,分别表示矩阵的行数和列数。
接下来的 n 行,每行包含 m 个整数。()
输出格式
输出一个整数,表示该子矩阵的和的最大值
显然,枚举左上与右下两个点肯定会超时,那么有没有方法可以降低枚举的复杂度呢?
我们想到,对于一个一维数组,我们可以通过枚举前缀和的方法做到的复杂度求出最大子段和。于是我们可以枚举行,在指定行范围内压缩为一维数组,再对其求最大子段和。当然如果不放心可以比较与的大小,枚举其中较小者即可。复杂度约。
码风极差,谨慎食用
点击查看代码
#include<bits/stdc++.h>
using namespace std;
long long n,m,a[500010],mi,s,ans=-0x3f3f3f3f;
int main()
{
scanf("%lld %lld",&n,&m);
for(long long i=1;i<=n;i++)
for(long long j=1;j<=m;j++)
scanf("%lld",a+i*m+2*i+j);
if(n<m)
{
for(long long i=1;i<=m;i++)
for(long long j=2;j<=n;j++)
a[j*m+2*j+i]+=a[j*m+2*j-m-2+i];
for(long long l=0;l<n;l++)
for(long long r=l+1;r<=n;r++)
{
s=0,mi=0;
for(long long i=1;i<=m;i++)
s+=a[r*m+2*r+i]-a[l*m+2*l+i],ans=max(ans,s-mi),mi=min(s,mi);
}
}
else
{
for(long long i=1;i<=n;i++)
for(long long j=2;j<=m;j++)
a[i*m+2*i+j]+=a[i*m+2*i+j-1];
for(long long l=0;l<m;l++)
for(long long r=l+1;r<=m;r++)
{
s=0,mi=0;
for(long long i=1;i<=n;i++)
s+=a[i*m+2*i+r]-a[i*m+2*i+l],ans=max(ans,s-mi),mi=min(s,mi);
}
}
printf("%lld\n",ans);
return 0;
}