AcWing 1413.矩形牛棚

思路:单调栈

其实这个需要转化一下问题,我们看到,这里让我们求最大矩形面积,并且里面会有被破坏的点。

暴力的话,我们肯定想到枚举上下边界,左右边界,然后判断里面的方格的状态是不是被破坏的,但是这样的循环复杂度会很大,所以我们需要想着优化才行。

那么,你可能会想到单调队列,因为这也是可以让时间复杂度变得简单的方法之一。但是不行,因为这里有妨碍点,也就是被破坏的点并不能讨论在内,况且我们需要连续的点,所以我们需要借助单调栈。

代码模拟:定义一个二维数组h,代表在每一行里面的最大高度,第二维其实就是不断地枚举地图的点,判断是不是有妨碍点,然后再取值的一个工具,并不是真的一列一列的枚举,而是每一行枚举每一列的一次,同时对每一列的高度进行更新的,这里需要大家细品,也就相当于是一个直方图的统计表一样。

我们取到了每一列的最大高度h[i],那么我们就会想到,这里矩形的长度该怎么办?

其实不难发现,如果是一个矩形,那么两个边界必须是相同的,并且高度一致。既然我们已经确定了高度了,只需要枚举每一列中的高度,求出来连续相同的高度最大值,然后乘以长度就行了。

这就要求这个矩形的两边的边界的旁边都必须是小于这个高度的,因为这样才能显出来这个矩形是最大面积,要是旁边两个边界的高度都是大于这个矩阵的高度,那么我们还真不能这样取最大值,因为还有更大的高度供我们选择。这里就要求我们用单调栈进行实现这个操作了。

上代码:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include <iomanip>
#include<sstream>
#include<numeric>
#include<map>
#include<limits.h>
#include<unordered_map>
#include<set>
#define int long long
#define MAX 3010
#define inf 0x3f3f3f3f
#define _for(i,a,b) for(int i=a;i<(b);i++)
using namespace std;
typedef pair<int, int> PII;
int n, m,k;
int counts;
int dx[] = { 0,1,0,-1};
int dy[] = { 1,0,-1,0 };
int h[MAX][MAX];
int st[MAX][MAX],top;
int stk[MAX];//stack
int l[MAX], r[MAX];
int solve(int h[]) {
    top = 0;
    h[0] = -1;
    h[m + 1] = -1;
    stk[++top] = 0;
    _for(i, 1, m + 1) {
        while (h[stk[top]] >= h[i])top--;
        l[i] = stk[top];
        stk[++top] = i;
    }
    top = 0;
    stk[++top] = m + 1;
    for (int i = m; i;i--) {
        while (h[stk[top]] >= h[i])top--;
        r[i] = stk[top];
        stk[++top] = i;
    } 
    int res = 0;
    _for(i, 1, m + 1) {
        res = max(res, h[i] * (r[i] - l[i] - 1));

    }
    return res;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> n >> m >> k;
    while (k--) {
        int x, y;
        cin >> x >> y;
        st[x][y] = 1;
    }
    _for(i, 1, n + 1) {
        _for(j, 1, m + 1) {
            if (!st[i][j]) {
                h[i][j] = h[i - 1][j] + 1;
            }
        }
    }
    int res = 0;
    _for(i, 1, n + 1) {
        res = max(res, solve(h[i]));
    }
    cout << res;
    return 0;
}

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值