0628Zn

分享一道题

题目描述
给定一个 n 行 m 列的整数矩阵,找到一个非空子矩阵,使得该子矩阵的和的值最大。子矩阵是指由原矩 阵的连续若干行和连续若干列组成的矩阵。

输入格式
第一行包含两个整数 n 和 m,分别表示矩阵的行数和列数。
接下来的 n 行,每行包含 m 个整数。(nm 1.6×105)
输出格式
输出一个整数,表示该子矩阵的和的最大值

显然,枚举左上与右下两个点肯定会超时,那么有没有方法可以降低枚举的复杂度呢?
我们想到,对于一个一维数组,我们可以通过枚举前缀和的方法做到Θ (n)的复杂度求出最大子段和。于是我们可以枚举行,在指定行范围内压缩为一维数组,再对其求最大子段和。当然如果不放心可以比较nm的大小,枚举其中较小者即可。复杂度约Θ(n3)
码风极差,谨慎食用

点击查看代码
#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;
}

posted on 2025-08-28 11:31  琬安与璃茗  阅读(8)  评论(0)    收藏  举报