【最大子矩形】糖果盒

1056: [OIBH] 糖果盒(Candy Box)

时间限制: 1 Sec   内存限制: 128 MB
提交: 15   解决: 6
[ 提交][ 状态][ 讨论版]

题目描述

一个被分为 n*m个格子的糖果盒,第 i 行第 j 列位置的格子里面有a[i][j]颗糖。本来tenshi打算送这盒糖果给某 PPMM 的,但是就在要送出糖果盒的前一天晚上,一只极其可恶的老鼠夜袭糖果盒,有部分格子被洗劫并且穿了洞。tenshi 必须尽快从这个糖果盒里面切割出一个矩形糖果盒,新的糖果盒不能有洞,并且 tenshi 希望保留在新糖果盒内的糖的总数尽量多。

输入

请帮tenshi设计一个程序 计算一下新糖果盒最多能够保留多少糖果。

输出

第一行有两个整数 n、m。第 i + 1 行的第 j 个数表示 a [ i ][ j ],如果这个数为 0 ,则表示这个位置的格子被洗劫过。


样例输入

3 41 2 3 45 0 6 310 3 4 0

样例输出

17

提示

数据范围:

1 ≤ n,m ≤ 1000

0 ≤ a [ i ][ j ]≤ 255

提示:

10 3 4 这个矩形的糖果数最大

来源

OIBH #1


悬线法,时间复杂度为O(nm)(还有一种扫描法,时间复杂度为O(S^2),S为障碍点个数,二者空间相同,可以分情况使用)

一开始我用的是标程的方法,把sum,l,r,maxl,maxr,height全部预处理出来。听OJ讲了之后,把那种方法和OJ的方法取长补短,总时间快了1s之多、空间少了一半


只预处理sum。l,r都只需要存储当前行的,maxl和maxr01滚动,height就地滚动(绝对位置)。需要注意的是,递推的时候如果不是障碍点,最左边能到达为l[j]和max[i-1,j]的最大值,最右边类似。如果是障碍点,则最把他maxl设为0,maxr设为m+1。因为到了下一行的时候,悬线高度变成1,maxl和maxr只由这一行决定,而和上一行无关,因此把上一行设为极值。


OJ的方法有一点不同的是对于maxl和maxr的处理方式,没有用递推的方法,而是向左右扫描的第一根比这一根悬线短的。我没有采用。


#include 

#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))

long n;long m;
long num[1010][1010];
long sum[1000][1010];
long l[1010];
long r[1010];
long maxl[2][1010];
long maxr[2][1010];
long height[1010];

int main()
{
	freopen("candy_box.in","r",stdin);
	freopen("candy_box.out","w",stdout);
	scanf("%ld%ld",&n,&m);
	for (long i=1;i0;j--)
		{
			if (num[i][j])
			{
				r[j] = r[j+1];
				maxr[i&1][j] = MIN(r[j],maxr[(i&1)^1][j]);
			}
			else
			{ 
				r[j] = j-1;
				maxr[i&1][j] = m+1;
			}
		}
 		for (long j=1;j


你可能感兴趣的:(NOI)