2019牛客暑期多校训练营(第二场) H Second Large Rectangle 【次大全1子矩阵和】【单调栈】

题意:

给你一个n*m的只有 1 和 0 的矩阵, 求全是1的第二大的子矩阵的面积。

题目链接:

https://ac.nowcoder.com/acm/contest/882/H

题解:

听说是陈年老题,可惜我不会

比赛一直在改就是不知道哪里错了qaq

比赛后看到有人用暴力写法A过了,惊了,我copy了他的代码交了一发,tle,牛客的服务器让我觉得好迷

然后看了队友的单调栈写法发现全是 1000*1000 个 1 暴力肯定会T  好迷啊

做法:

首先,先预处理,把h[i][j] 作为以h[i][j]作为最低点的连续的1的长度, 如果该点为0,则长度为 0。

然后对每一行进行单调栈处理, 对计算的结果取值,由于使用单调栈,我们求得是次大子矩阵,所以要把包含在最大子矩阵得次大

子矩阵的情况算进去,所以对于取值的时候要特判 (x-1,y)  和 (x,y-1),x代表长,y代表宽。

AC_code:

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

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cstring>
#include<cstdio>
//#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define mod 1e9 + 7
#define line printf("--------------");
using namespace std;
int h[maxn][maxn];
int maxx = 0, maxx1 = 0;
int calc(int x, int y) {
	int ans = x * y;
	if(ans > maxx) {
		maxx1 = maxx;
		maxx = ans;
	} else if(ans > maxx1) {
		maxx1 = ans;
	}
}
int main() {
	int n, m;
	cin>>n>>m;
	char s;
	memset(h, 0, sizeof(h));
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			cin>>s;
			if(s == '1') {
				h[i][j] = h[i-1][j] + 1;
			}
		}
	}

	for(int i = 1; i <= n; i++) {
		stack<int>st;
		st.push(0);
		h[i][0] = -2;//防止栈空 
		h[i][m + 1] = -1;
		for(int j = 1; j <= m+1; j++) {
			while (h[i][st.top()] > h[i][j]) {
				int index = st.top();
				st.pop();
				int d = j-1-st.top(); //当前位置往前  
				calc(d, h[i][index]);//最大的情况 
				
				calc(d-1, h[i][index]);//包含在最大内的次大的情况 
				calc(d, h[i][index]-1);
			}
			st.push(j);
		}
	}
	cout<<maxx1<<endl;


	return 0;
}

暴力代码(WA):

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

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cstring>
#include<cstdio>
//#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define mod 1e9 + 7
#define line printf("--------------");
using namespace std;
int h[maxn][maxn];
int main() {
	int n, m;
	int maxx = 0, maxx1 = 0;
	cin>>n>>m;
	char s;
	memset(h, 0, sizeof(h));
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			cin>>s;
			if(s == '1') {
				h[i][j] = h[i-1][j] + 1;
			}
		}
	}
	
	for(int i = 1; i <= n; i++) {	
		for(int j = 1; j <= m; j++) {
			int hh = h[i][j];
            int d = 1;
			while(hh != 0){
				int ans = hh*d;
				if(ans > maxx){
					maxx1 = maxx;
					maxx = ans;
				}else if(ans > maxx1){
					maxx1 = ans;
				}
				hh = min(hh, h[i][j+d]);
				++d;
			}
		}
	}
	cout<<maxx1<<endl;


	return 0;
}

 

全部评论

相关推荐

行云流水1971:这份实习简历的优化建议: 结构清晰化:拆分 “校园经历”“实习经历” 板块(当前内容混杂),按 “实习→校园→技能” 逻辑排版,求职意向明确为具体岗位(如 “市场 / 运营实习生”)。 经历具象化:现有描述偏流程,需补充 “动作 + 数据”,比如校园活动 “负责宣传” 可加 “运营公众号发布 5 篇推文,阅读量超 2000+,带动 300 + 人参与”;实习内容补充 “协助完成 XX 任务,效率提升 X%”。 岗位匹配度:锚定目标岗位能力,比如申请运营岗,突出 “内容编辑、活动执行” 相关动作;申请市场岗,强化 “资源对接、数据统计” 细节。 信息精简:删减冗余表述(如重复的 “负责”),用短句分点,比如 “策划校园招聘会:联系 10 + 企业,组织 200 + 学生参与,到场率达 85%”。 技能落地:将 “Office、PS” 绑定经历,比如 “用 Excel 整理活动数据,输出 3 份分析表;用 PS 设计 2 张活动海报”,避免技能单独罗列。 优化后需强化 “经历 - 能力 - 岗位需求” 的关联,让实习 / 校园经历的价值更直观。 若需要进一步优化服务,私信
实习,投递多份简历没人回...
点赞 评论 收藏
分享
不会做题的小熊:我感觉我就算是找不到工作,我也不会作弊进去,作弊进去感觉一方面是自己不踏实,其次就是都靠作弊了,那后面肯定工作的心态是不一样的,没有一种内驱力。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务