题干:

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

题目描述

Given a N×MN \times MN×M binary matrix. Please output the size of second large rectangle containing all "1"\texttt{"1"}"1".

Containing all "1"\texttt{"1"}"1" means that the entries of the rectangle are all "1"\texttt{"1"}"1".

A rectangle can be defined as four integers x1,y1,x2,y2x_1, y_1, x_2, y_2x1​,y1​,x2​,y2​ where 1≤x1≤x2≤N1 \leq x_1 \leq x_2 \leq N1≤x1​≤x2​≤N and 1≤y1≤y2≤M1 \leq y_1 \leq y_2 \leq M1≤y1​≤y2​≤M. Then, the rectangle is composed of all the cell (x, y) where x1≤x≤x2x_1 \leq x \leq x_2x1​≤x≤x2​ and y1≤y≤y2y_1 \leq y \leq y2y1​≤y≤y2. If all of the cell in the rectangle is "1"\texttt{"1"}"1", this is a valid rectangle.

Please find out the size of the second largest rectangle, two rectangles are different if exists a cell belonged to one of them but not belonged to the other.

输入描述:

 

The first line of input contains two space-separated integers N and M.
Following N lines each contains M characters cijc_{ij}cij​.

1≤N,M≤10001 \leq N, M \leq 10001≤N,M≤1000
N×M≥2N \times M \geq 2N×M≥2
cij∈"01"c_{ij} \in \texttt{"01"}cij​∈"01"

输出描述:

 

Output one line containing an integer representing the answer. If there are less than 2 rectangles containning all "1"\texttt{"1"}"1", output "0"\texttt{"0"}"0".

示例1

输入

复制

1 2
01

输出

复制

0

示例2

输入

复制

1 3
101

输出

复制

1

题目大意:

给定一个N*M的01矩阵,求 不严格第二大 的全1子矩阵。(严格第二大就是,你求出的值必须和第一大的 值不同)

解题报告:

求第一大的是单调栈裸题。这题是第二大通过观察不难发现,最终答案一定是某个候选的最大子矩阵的子矩阵。而在这些子矩阵中,肯定是去掉某一行或者去掉某一列是最优的。所以做法就是先O(N*M)求出所有最大子矩阵,然后枚举这些矩阵,维护最大值和次大值就好了。但是要注意去重,因为假设是一行三列"111"这种情况的话,那答案肯定是不对的,因为你以每一个1为底都是对应同一个矩形,也就是这样会算重复。

这里我采用的处理办法是在记录最大值次大值的同时记录对应的左端点,右端点和高。(虽然按理来说不能记录高,而应该记录下底和上底,但是这个题我是按照下底进行遍历的,而遍历每一行的时候都清空了我上一行维护的“左端点,右端点和高”,所以这样就足够去重的要求了,所以不需要记录下底和上底)。虽然去重是没有问题的,但是其实在考虑矩阵的时候我这样做不是严格正确的,因为你去掉某一列的时候,默认是去掉了最右列,按理来说也可以去掉最左列呀,,也就是说本身会生成两个次小子矩阵的你只考虑了一个,所以程序其实是有点问题,但是因为这个题求的是第2大,所以肯定还是能AC的。因为你求的这些肯定比最大子矩阵要小,所以肯定符合要求,但是如果题目让你求第三大的,这样就不太行了。。。你得把:去掉左列,去掉右列,去掉上行,去掉下行,都加入考虑中,才是正确答案。。(或许这题还可以再出一遍??emmm)

以上是我采用的处理办法,但是不具有通用性,他如果让你求第8大,那你维护八个变量不成?所以这里正解给出的是加入vector中,然后对vector排序,然后去重(这一点一定别忘了,但是你要是这么写的话就得记录对应的左端点,右端点和下底上底了,不能只记录高了),然后输出第8大。(因为这题是第二大所以直接上pq维护两个元素也行)

AC代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<stack>using namespace std;
const int MAX = 1000 + 5;
int n,m;
int maze[MAX][MAX];
int L[MAX],R[MAX];void getl(int i) {stack<int > sk;//要找他左侧的第一个严格比他小的元素 所以需要从左向右维护一个严格单调递增栈for(int j = 1; j<=n; j++) {while(!sk.empty() && maze[i][sk.top() ]>=maze[i][j] ) sk.pop();if(sk.empty() ) L[j] = 0;else L[j] = sk.top();sk.push(j);}}
void getr(int i) {stack<int > sk;//要找他右侧的第一个严格比他小的元素 所以需要从右向左维护一个严格单调递增栈for(int j = n; j>=1; j--) {while(!sk.empty() && maze[i][sk.top() ]>=maze[i][j] ) sk.pop();if(sk.empty() ) R[j] = n+1;else R[j] = sk.top();sk.push(j);}}
void init() {for(int i = 1; i<=m; i++)for(int j = 1; j<=n; j++)maze[i][j]=0;
}
int main()
{while(~scanf("%d %d",&m,&n) ) {//m行n列init();for(int i = 1; i<=m; i++) {for(int j = 1; j<=n; j++) {int tmp;scanf("%1d",&tmp);if(tmp==1) {maze[i][j]=maze[i-1][j]+1;}}}//至此我们已经有了截止第i行的(1~i)每一个j的连续高度,int maxx=0,ci = 0,tmp,tmp1,tmp2,mx1=-1,mx2=-1,mh=-1;for(int i = 1; i<=m; i++) {getl(i);getr(i);mx1=-1,mx2=-1,mh=-1;for(int j = 1; j<=n; j++) {tmp = maze[i][j] * (R[j] - L[j] -1);tmp1 = maze[i][j] * (R[j] - L[j] -2);tmp2 = (maze[i][j]-1) * (R[j] - L[j] -1);int curl=L[j]+1,curr = R[j]-1,curh = maze[i][j];if(tmp > maxx) {ci = maxx;mx1=curl,mx2=curr,mh=curh;maxx = tmp;}else if(tmp > ci && (mx1!=curl || mx2!=curr || mh!=curh)) {ci = tmp;}if(tmp1 >= tmp2) {tmp = tmp1;curr--;}else {tmp = tmp2;curh--;}
//              tmp = max(tmp1,tmp2);if(tmp > maxx) {ci = maxx;mx1=curl,mx2=curr,mh=curh;maxx = tmp;}else if(tmp > ci && (mx1!=curl || mx2!=curr || mh!=curh)) {ci = tmp;}}
//          printf("\n");}printf("%d\n",ci);}return 0 ;}
/*
1 3
111
*/

然后你会发现简短好多:(忽然发现好像不用考虑减一行呀、、因为那肯定在上一行当下底的时候算过了、、)

(其实还是因为单调栈的打开方式不太一样,我是遍历到第i个元素的时候处理第i个元素,然后push(i)进去,他是pop(j)的时候才开始处理每一个j,我要是这么写的话应该也短不少,而且有的时候只能用第二种方式,比如后面那次牛客多校、、)

这样写的意思就是把所有宽度的缩减都考虑进去了。但是这样写的话应该可以卡T掉,,因为你构造一个左下全1的下三角矩阵,就能卡成O(N*M*M)、、因为他那个cnt的动作太耗时了。(本来写的是最下面那个代码)

#include<bits/stdc++.h>
using namespace std;
const int M = 1e3+5;
int dp[M][M];
int ddz[M],w[M];
vector<int> ans;
int n,m;void solve(int *f){int top = 0;ddz[top] = -1;f[m+1] = -1;for(int i=1;i<=m+1;i++){if(ddz[top] <= f[i]) ddz[++top] = f[i];else {int cnt = 0;//接下来把所有宽度的都加进去while(top && ddz[top] > f[i]) {cnt++;ans.push_back(ddz[top] * cnt);top--;}while(cnt--) ddz[++top] = f[i];ddz[++top] = f[i];}}
}int main(){char c[M];while(~scanf("%d%d",&n,&m)) {ans.clear();for(int i=1;i<=n;i++){scanf("%s",c);for(int j=1;j<=m;j++) dp[i][j] = c[j-1] == '0'? 0 : dp[i-1][j]+1;}for(int i=1;i<=n;i++) solve(dp[i]);sort(ans.begin(),ans.end());/*考虑特例*/int sz = ans.size();if(sz<=1) printf("0\n");printf("%d\n", ans[sz-2]);}return 0;
}

他本来的solve函数是这么写的:

void solve(int *f){int top = 0;ddz[top] = -1;f[m+1] = -1;for(int i=1;i<=m+1;i++){/*等于时是否弹出这需要自己注意一下,就是严不严格单调的选择*/if(ddz[top]<f[i]) ddz[++top]=f[i],w[top]=1;else{int width = 0;/*此处注意要先加宽度*/while(top&&f[i]<ddz[top]){ width+=w[top],ans.push_back(ddz[top]*width),ans.push_back(ddz[top]*(width-1));top--;}/*我的做法是 : 等于是加入,不严格单调*/ddz[++top]=f[i],w[top]=width+1;}}
}

【2019牛客暑期多校训练营(第二场) - H】Second Large Rectangle(单调栈,全1子矩阵变形)相关推荐

  1. [题解] 2019牛客暑期多校第三场H题 Magic Line

    题目链接:https://ac.nowcoder.com/acm/contest/883/H 题意:二维平面上有n个不同的点,构造一条直线把平面分成两个点数相同的部分. 题解:对这n个点以x为第一关键 ...

  2. 2019牛客暑期多校训练营(第三场)H.Magic Line

    2019牛客暑期多校训练营(第三场)H.Magic Line 题目链接 题目描述 There are always some problems that seem simple but is diff ...

  3. 2019牛客暑期多校训练营(第五场)C generator 2 (BSGS)

    2019牛客暑期多校训练营(第五场)C generator 2 思路 x0=x0x_0 = x_0x0​=x0​ x1=a∗x0∗bx_1 = a * x_0 * bx1​=a∗x0​∗b x2=a∗ ...

  4. 2019牛客暑期多校训练营(第四场)----E- triples II

    首先发出题目链接: 链接:https://ac.nowcoder.com/acm/contest/884/E 来源:牛客网 涉及:位运算,容斥定义,dp 点击这里回到2019牛客暑期多校训练营解题-目 ...

  5. 暑假N天乐【比赛篇】 —— 2019牛客暑期多校训练营(第二场)

    最近几天都没写博客,真是没什么时间写了,专题卡着,一周四场比赛,场场爆零,补题都补傻了.第一场还差两题可能今天补掉吧,昨天的杭电也是完全没动,感觉...很烦 第二场牛客断断续续也是补了几天...大概一 ...

  6. 【2019牛客暑期多校训练营(第二场)- F】Partition problem(dfs,均摊时间优化)

    题干: 链接:https://ac.nowcoder.com/acm/contest/882/F 来源:牛客网 Given 2N people, you need to assign each of ...

  7. 【2019牛客暑期多校训练营(第二场)- E】MAZE(线段树优化dp,dp转矩阵乘法,线段树维护矩阵乘法)

    题干: 链接:https://ac.nowcoder.com/acm/contest/882/E?&headNav=acm 来源:牛客网 Given a maze with N rows an ...

  8. 【2019牛客暑期多校训练营(第二场) - D】Kth Minimum Clique(bfs,tricks)

    题干: 链接:https://ac.nowcoder.com/acm/contest/882/D 来源:牛客网 Given a vertex-weighted graph with N vertice ...

  9. 2019牛客暑期多校训练营(第二场)H Second Large Rectangle

    题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目描述 Given a N×M binary matrix. Please output the siz ...

最新文章

  1. 基于visual Studio2013解决面试题之0403串联字符串
  2. 如何超越console.log并充分利用浏览器的调试控制台
  3. 简单BP网络识别数码表字符
  4. es5 - array - concat
  5. 华为机试题1:计算字符串最后一个单词的长度,单词以空格隔开。
  6. 【机器学习】朴素贝叶斯代码练习
  7. 卡耐基大学计算机专业分类,卡内基梅隆大学计算机专业
  8. natty的异步通信框架_OpenHub框架进行的异步通信
  9. javascript中数据访问性能优化简析
  10. 计算机二级c选择题怎么准备,马上计算机二级考试,你准备得怎么样了?
  11. python核心编程:第六章。
  12. 数组、字符串长度的计算(转)
  13. ABP框架详解(一)ABPBootstrapper
  14. Golang: How to sort struct with multiple sort parameters?
  15. Android 学习笔记(十五) Activity-GalleryView
  16. 常见黑客渗透测试工具
  17. 业界 | 福布斯:2018年机器学习试点及实施数量将翻倍
  18. 身份证读卡器 护照阅读器,如何能做到读取多证件呢?
  19. 2021年9月国产数据库排行榜-墨天轮:达梦奋起直追紧逼OceanBase,openGauss反超PolarDB再升一位
  20. 【CV/Matlab系列】基于图像处理的苹果质量检测和分级系统【含Matlab源码】

热门文章

  1. Microsoft SQL Server 2005数据库安装
  2. [Leedcode][JAVA][第209题][长度最小的子数组][滑动窗口][前缀和][二分查找][双指针]
  3. php上传文件损坏,PHP 上传文件故障排除
  4. 12v小型电机型号大全_鄂破碎机型号大全图,小型鄂破碎机价格
  5. 波士顿大学计算机与传媒专业,波士顿大学传媒专业好吗
  6. java vbs_VBS基础篇 - vbscript Dictionary对象
  7. 调用另一个cpp的变量_再谈条件变量—从入门到出家
  8. css transtion不生效_CSS中transition属性不起作用的原因及解决方法
  9. C++设计模式之 简单工厂模式讲解(历史上最简单明白的例子)
  10. 是否要运行此应用程序_使用Delve调试Go应用程序