最大子矩阵-单调栈 、去重

链接:https://ac.nowcoder.com/acm/contest/888/A
来源:牛客网
 

All-one Matrices

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

Gromah and LZR entered the great tomb, the first thing they see is a matrix of size n×mn\times mn×m, and the elements in the matrix are all 00_{}0​ or 11_{}1​.

LZR finds a note board saying "An all-one matrix is defined as the matrix whose elements are all 11_{}1​, you should determine the number of all-one submatrices of the given matrix that are not completely included by any other all-one submatrices".

Meanwhile, Gromah also finds a password lock, obviously the password should be the number mentioned in the note board!

Please help them determine the password and enter the next level.

输入描述:

 

The first line contains two positive integers n,mn,m_{}n,m​, denoting the size of given matrix.

Following nn_{}n​ lines each contains a string with length mm_{}m​, whose elements are all 00_{}0​ or 11_{}1​, denoting the given matrix.

1≤n,m≤30001\le n,m \le 30001≤n,m≤3000

输出描述:

Print a non-negative integer, denoting the answer.

示例1

输入

复制

3 4
0111
1110
0101

输出

复制

5

说明

The 5 matrices are (1,2)−(1,4),  (1,2)−(2,3),  (1,2)−(3,2),  (2,1)−(2,3),  (3,4)−(3,4)(1,2)-(1,4), \; (1,2)-(2,3), \; (1,2)-(3,2), \; (2,1)-(2,3), \; (3,4)-(3,4)_{}(1,2)−(1,4),(1,2)−(2,3),(1,2)−(3,2),(2,1)−(2,3),(3,4)−(3,4)​.

先对每个点的 高度(单调栈维护高度)、前缀和(判断当前行是否为矩阵的底)预处理

之后对每一行进行相同操作处理:

1.求当前点的矩阵的左端点

2.求当前点的矩阵的右端点(单调栈维护 最近的一个高度小于自己的下标,栈顶下标+/-  1为边界端点)

3.求当前行的矩阵对答案的贡献 并 去重处理(此处单调栈维护最左边的 高度<= 自己的下标,如果等于自己则为同一个矩阵不计算)

#include<bits/stdc++.h> 
using namespace std;
char a[3004][3004];
int h[3004][3003],sum[3003][3003];
int R[3003],L[3003];
int m,n;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",a[i]+1);
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='1') h[i][j]=h[i-1][j]+1;//高度预处理 
			sum[i][j]+=sum[i][j-1]+a[i][j]-'0';//前缀和预处理
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)	
	{
		stack<int> stk;
		stk.push(0);
		for(int j=1;j<=m;j++)//求L[j] 左边界 单调栈模板 
		{
		
			while(!stk.empty()&&h[i][j]<=h[i][stk.top()]) stk.pop();
			//维护单调性处理
			if(stk.empty()) L[j]=0;//h[i][j]高度为0时进入此语句 
			else L[j]=stk.top()+1;//当前栈顶已经是 最近的小于自己的数 
			
			stk.push(j);
		}
		while(!stk.empty()) stk.pop();
		//清空栈 
		stk.push(m+1);
		for(int j=m;j;j--)//求R[j] 右边界
		{
			while(!stk.empty()&&h[i][j]<=h[i][stk.top()]) stk.pop();
			//维护单调性处理
			if(stk.empty()) R[j]=0;
			else R[j]=stk.top()-1;
			
			stk.push(j);
		}
		
		while(!stk.empty()) stk.pop();
		for(int j=1;j<=m;j++) 
		{
			if(h[i][j]==0)//高度为0  不贡献答案 且清空单调栈 
			{
				while(!stk.empty()) stk.pop();
				continue;
			}
			while(!stk.empty()&&h[i][j]<h[i][stk.top()]) stk.pop();
			//维护单调性处理 
			if(stk.empty()||h[i][j]!=h[i][stk.top()])//去重判断--高度不相同  
			{
				int l=L[j];
				int r=R[j];
				if(sum[i+1][r]-sum[i+1][l-1]!=R[j]-L[j]+1)//下面对应的一行  无连续1 
				{
					ans++;
				}
				stk.push(j);//!!!!重新放入 
			}	
		}	
	}
	printf("%d\n",ans);
	
	
}
发布了44 篇原创文章 · 获赞 6 · 访问量 1197

猜你喜欢

转载自blog.csdn.net/qq_43868883/article/details/99194023