题意:给出由01组成的矩阵,求求全是1的次大子矩阵。

思路:

单调栈

全是1的最大子矩阵的变形,不能直接把所有的面积存起来然后排序取第二大的,因为次大子矩阵可能在最大子矩阵里面,比如:

1 0 0
1 1 1
1 1 1

有篇博主的代码细节处理的很好,由于矩阵每行的长度一致,则不必重复在数组末尾标记0;然后由于j是从1,最开始如果push进0的话,有两个好处:

  1.可以不受栈之前“残留”的元素m+1的影响

  2.不用再判断栈是某为空来确定wid的值

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 7; int n, m, ans;
string str[N];
int h[N], mx1, mx2;
stack <int> s; void solve(int x)
{
if(x > mx1)
mx2 = mx1, mx1 = x;
else if(x > mx2) mx2 = x;
}
int main()
{
scanf("%d%d",&n, &m);
for(int i = 1; i <= n; i++) {
cin >> str[i];
for(int j = 1; j <= m; j++) {
if(str[i][j-1] == '1') h[j] += 1;
else h[j] = 0;
}
s.push(0);
for(int j = 1; j <= m + 1; j++) {
while(h[j] < h[s.top()]) {
int index = s.top(); s.pop();
int x = j - 1 - s.top(), y = h[index];
solve(x * y);
solve((x - 1)* y);
solve(x * (y - 1));
}
s.push(j);
}
}
cout << mx2 << endl;
}

悬线法

通过悬线法,可以找到以点(i,j)为底的极大矩形。

u[i][j]、l[i][j]、r[i][j]分别表示以为底的极大矩形的上边界,左边界,右边界;

首先预处理:找到点(i,j)可以沿伸的的上端点、左端点,右端点 (dp)

For i = 1 to n
For j = 1 to m
u[i][j] = (i-1,j)==1 ? u[i-1][j] : i;
l[i][j] = (i,j-1)==1 ? l[i][j-1] : j;
For j = m to 1
r[i][j] = (i,j+1)==1 ? r[i][j+1] : j;

如图找到了(4,3)  的   上端点、左端点,右端点,但是这些边界并没有组成一个矩形,可以(4,3)的上端点为上边界,找到左右边界,这样就可以找到一个以点(4,3)为底、以点(4,3)上界为高的极大矩形。

For i = 1 to n
For j = 1 to m
if (i-1,j)==1
l[i][j] = max(l[i][j], l[i-1][j]
r[i][j] = min(r[i][j], r[i-1][j]
矩形面积就是 (r[i][j] − l[i][j] + 1) ∗ (i − u[i][j] + 1)
Code

#include<bits/stdc++.h>
using namespace std; const int N = 1e3+100; int n, m;
int g[N][N];
int u[N][N], l[N][N], r[N][N];
int hh, ll, rr, bb;
char str[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++){
scanf("%s",str+1);
for(int j = 1; j <= m; j++ ){
if(str[j] == '1') g[i][j] = 1;
else g[i][j] = 0;
}
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
u[i][j] = l[i][j] = r[i][j] = 0; for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(g[i][j] == 0) continue;
u[i][j] = g[i-1][j] == 1 ? u[i-1][j] : i;
l[i][j] = g[i][j-1] == 1 ? l[i][j-1] : j;
}
for(int j = m; j >= 1; j--){
if(g[i][j] == 0) continue;
r[i][j] = g[i][j+1] == 1 ? r[i][j+1] : j;
}
}
int ans = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(g[i][j] == 0) continue;
if(g[i-1][j] == 1) {
l[i][j] = max(l[i][j], l[i-1][j]);
r[i][j] = min(r[i][j], r[i-1][j]);
}
if(ans<(r[i][j]-l[i][j]+1)*(i-u[i][j]+1)){
hh = u[i][j] , bb =i;
rr = r[i][j],ll=l[i][j];
ans = (r[i][j]-l[i][j]+1)*(i-u[i][j]+1);
}
}
}
int ans2 = max((rr-ll)*(bb-hh+1), (rr-ll +1)*(bb-hh));
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(g[i][j] == 0) continue;
if(hh==u[i][j]&&bb==i&&ll==l[i][j]&&rr==r[i][j])
continue;
if(ans2<(r[i][j]-l[i][j]+1)*(i-u[i][j]+1)){
ans2=(r[i][j]-l[i][j]+1)*(i-u[i][j]+1);
}
}
}
cout << ans2 << endl;
return 0;
}

悬线法的学习可以参考这篇博客(小声bb:虽然感觉现在没什么用,还不如单调栈)

https://blog.csdn.net/dbc_121/article/details/77503611

2019牛客暑期多校训练营(第二场) H-Second Large Rectangle(单调栈)的更多相关文章

  1. 牛客多校第二场H Second Large Rectangle 单调栈or悬线法

    Second Large Rectangle 题意 给出n*m的01矩阵,问由1组成的第二大的矩阵的大小是多少? 分析 单调栈(or 悬线法)入门题 单调栈 预处理出每一个点的最大高度,然后单调栈每一 ...

  2. 2019 牛客暑期多校 第二场 H Second Large Rectangle (单调栈)

    题目:https://ac.nowcoder.com/acm/contest/882/H 题意:一个大的01矩阵,然后现在要求第二大的全一矩阵是多少 思路:在这里我们首先学习一下另一个东西,怎么求直方 ...

  3. 2020牛客暑期多校训练营 第二场 K Keyboard Free 积分 期望 数学

    LINK:Keyboard Free 我要是会正经的做法 就有鬼了. 我的数学水平没那么高. 三个同心圆 三个动点 求围成三角形面积的期望. 不会告辞. 其实可以\(n^2\)枚举角度然后算出面积 近 ...

  4. 2020牛客暑期多校训练营 第二场 J Just Shuffle 置换 群论

    LINK:Just Shuffle 比较怂群论 因为没怎么学过 置换也是刚理解. 这道题是 已知一个置换\(A\)求一个置换P 两个置换的关键为\(P^k=A\) 且k是一个大质数. 做法是李指导教我 ...

  5. 2020牛客暑期多校训练营 第二场 I Interval 最大流 最小割 平面图对偶图转最短路

    LINK:Interval 赛时连题目都没看. 观察n的范围不大不小 而且建图明显 考虑跑最大流最小割. 图有点稠密dinic不太行. 一个常见的trick就是对偶图转最短路. 建图有点复杂 不过建完 ...

  6. 2020牛客暑期多校训练营 第二场 C Cover the Tree 构造 贪心

    LINK:Cover the Tree 最受挫的是这道题,以为很简单 当时什么都想不清楚. 先胡了一个树的直径乱搞的贪心 一直过不去.后来意识到这类似于最经典长链剖分优化贪心的做法 然后那个是求最大值 ...

  7. 2020牛客暑期多校训练营 第二场 B Boundary 计算几何 圆 已知三点求圆心

    LINK:Boundary 计算几何确实是弱项 因为好多东西都不太会求 没有到很精通的地步. 做法很多,先说官方题解 其实就是枚举一个点 P 然后可以发现 再枚举一个点 然后再判断有多少个点在圆上显然 ...

  8. 2020牛客暑期多校训练营 第二场 A All with Pairs 字符串hash KMP

    LINK:All with Pairs 那天下午打这个东西的时候状态极差 推这个东西都推了1个多小时 (比赛是中午考试的我很困 没睡觉直接开肝果然不爽 一开始看错匹配的位置了 以为是\(1-l\)和\ ...

  9. 2019牛客暑期多校训练营(第九场) D Knapsack Cryptosystem

    题目 题意: 给你n(最大36)个数,让你从这n个数里面找出来一些数,使这些数的和等于s(题目输入),用到的数输出1,没有用到的数输出0 例如:3  4 2 3 4 输出:0 0 1 题解: 认真想一 ...

随机推荐

  1. 解锁Renderbus客户端使用新技巧----快速渲染效果图篇

    度娘说,效果图最基本的要求就是:应该符合事物的本身尺寸,不能为了美观而使用效果把相关模型的尺寸变动,那样的效果图不但不能起到表现设计的作用,反而成为影响设计的一个因素.可见高效渲染效果图是都是当下我们 ...

  2. 【C++】《C++ Primer 》第九章

    第九章 顺序容器 一.顺序容器概述 顺序容器(sequential container):为程序员提供了控制元素存储和访问顺序的能力.这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应. 不同 ...

  3. 剑指Offer58-左转字符串

    题目 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=" ...

  4. Vue基础语法与指令

    项目初始化 用vscode打开终端,输入npm init -y生成package.json 然后安装vue npm install vue 需要注意的是,我遇到了这个问题 出现原因:文件夹名和生成的p ...

  5. Linux简单Shell脚本监控MySQL、Apache Web和磁盘空间

    Linux简单Shell脚本监控MySQL.Apache Web和磁盘空间 1. 目的或任务 当MySQL数据库.Apache Web服务器停止运行时,重新启动运行,并发送邮件通知: 当服务器磁盘的空 ...

  6. Burp suite的系列介绍 (1)

    前言 为了进行Web安全方面的学习,Burp suite是必备的工具之一,我们将会从多个模块进行逐步的学习. Burp suite的应用场景 1.HTTP服务端接口测试. 2.HTTP客户端和HTTP ...

  7. 攻防世界—pwn—cgpwn2

    题目分析 题目提示 checksec检查文件保护机制 使用ida查看伪代码 hello函数存在溢出,与level2类似 信息收集 system地址 name的地址 编写脚本 from pwn impo ...

  8. 简易双色球dome分享

    代码如下: <style type="text/css"> div {font-weight: bold;text-align: center;} .tone{widt ...

  9. 浅谈java中线程和操作系统线程

    在聊线程之前,我们先了解一下操作系统线程的发展历程,在最初的时候,操作系统没有进程线程一说,执行程序都是串行方式执行,就像一个队列一样,先执行完排在前面的,再去执行后面的程序,这样的话很多程序的响应就 ...

  10. h3c交换机配置ssh密码验证登录方式

    一.背景: 1.由于PC机串口不支持热插拔,请不要在交换机带电的情况下,将串口插入或者拔出PC机.当连接PC和交换机时,请先安装配置电缆的DB-9端到PC机,再连接RJ-45到交换机:在拆下时,先拔出 ...