2019牛客暑期多校训练营(第八场)A All-one Matrices【单调栈】【前缀和】

本文介绍了一种使用单调栈和前缀和算法解决特定矩阵问题的方法,即在n*m的01矩阵中寻找那些不会被其他全1矩阵覆盖的所有全1矩阵。通过预处理每个点向上连续的1的个数,并利用单调栈来判断矩阵是否能向上下左右扩展,最终实现了O(nm)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

输入 n*m 的01矩阵
有多少个全1矩阵,不会被其他的全1矩阵覆盖

题目链接:

https://ac.nowcoder.com/acm/contest/888/A

题解:

单调栈+前缀和
对于每-一个格子(ij) , 记up[il[j]为其向上的连续的1的个数。
然后枚举每一行作为矩阵的底边所在行,从前往后枚举每一列 ,枚举时候,记录更新一个pos值,判断下一行该列为不为0, 方便为下面能否向下扩展做判断, 维护一个关于up[i][j]的单调上升的栈,对于栈中每一个up值,那么每当有元素退栈的时候,判断与后一个元素是否相等,相等则可以向右扩展,不进行任何操作, 栈内前一个元素为左边所能到达最远位置, 判断一个下一行该列的连续1所能到达最左边位置pos是否大于该位置, 是则说明不能向下扩展,我们可以得到一一个全1矩阵(i+up-1,sta[top-1] + 1)-(ij) ,且不能向上下左右扩展了。
时间复杂度: O(nm)

AC_code:

/*
Algorithm:
Author: anthony1314
Creat Time:
Time Complexity:
*/

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e3+5;
int up[maxn][maxn], sta[maxn];//每个点的其向上的连续的1的个数  栈
char c[maxn][maxn];
int n, m;
int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++){
		scanf("%s", c[i]+1);
	}
	for(int i = 1; i <= n; i++){//预处理 
		for(int j = 1; j <= m; j++){
			if(c[i][j] == '0'){
				up[i][j] = 0;
			}else {
				up[i][j] = up[i-1][j] + 1;
			}
		}
	}
	int ans = 0;
	for(int i = 1; i <= n; i++){
		int pos = 0, top = 0;
		sta[++top] = 0;
		if(c[i][1] == '0'){//放入第一个元素 
			sta[top] = 1;
		}else {
			sta[++top] = 1;
		}
		for(int j = 1; j <= m; j++){
			if(j != 1){// 第一个已经如果栈了 不必入了 
				sta[++top] = j;
			}
			if(c[i+1][j] == '0' || i == n) {//判断下一行为不为0和是不是最后一行 为0和最后一行说明这是矩形下一行所能向左扩展最远位置 
				pos = j; 
			}
			while(top > 0 && up[i][sta[top]] >= up[i][j+1]){//栈顶元素 大于等于 下一个数  则退栈 
				if(top > 1 && sta[top-1] < pos && c[i][j] != '0' && up[i][sta[top]] > up[i][j+1]) {//判断退栈元素是否无法向右扩展 
					ans++;
				}
				top--;
			}
		}
		cout<<ans<<endl; 
	}
	cout<<ans<<endl; 
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值