2019牛客暑期多校训练营(第二场场)_H题Second Large Rectangle

题目链接: https://ac.nowcoder.com/acm/contest/882/H

思路:(转载自: https://www.cnblogs.com/pisceskkk/p/11229105.html)
首先考虑求最大矩形:

不妨考虑以第i行为底边的矩形,那么就转化成直方图求最大矩形面积。

如图
2019牛客暑期多校训练营(第二场场)_H题Second Large Rectangle_第1张图片
当我们遇到第三列时,第二列的高度已经不能拓展,因此将其清算掉,同时将第三列高度加入栈中。

即使用单调栈维护所有高度中最靠右且小于当前高度的位置(注意单调)。

进而考虑求第二大,情况有二,所有完整的尽量大的矩形中第二大,或者尽量大的矩形去掉一行或者一列。由于我们按行以此求解,只需要额外考虑去掉一列的情况就OK。

单调栈的一道经典题

力扣: 柱状图中最大的矩形: https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
同样也是用单调栈去维护一个非递减序列

代码

#include 
using namespace std;
int mp[1005][1005];
int sum[1005];
int main()
{
    ios::sync_with_stdio(false);
    int n, m;
    while(cin >> n >> m){
        int maxn = 0, minn = 0;
        string s;
        for(int i = 1; i <= n; i++){
            cin >> s;
            sum[i] = 0;
            for(int j = 1; j <= m; j++){
                mp[i][j] = (s[j - 1] - '0');
            }
            mp[i][m + 1] = 0;
        }

        for(int i = 1; i <= n; i++){
            stack<int> st;
            int ans;
            st.push(0); // 设置矩形的坐界限
            for(int j =  1; j <= m + 1; j++){
                sum[j] = (mp[i][j] == 1 ? sum[j] + 1 : 0);
                while(st.size() > 1 && sum[j] <= sum[st.top()]){
                    int k = st.top();
                    st.pop();
                    ans = sum[k] * ((j - 1) - st.top());  // 宽 * 底面长
                    if(ans > maxn){
                        minn = maxn;
                        maxn = ans;
                        ans -= sum[k]; 		//因为我们求的第二大 所以我们要尝试去掉一行或者一列再去与第二大做比较, 因为我们是按行来求解的所以我们只要尝试去掉一列即可, 即宽 * (底面长 - 1)
                        if(ans > minn){
                            minn = ans;
                        }
                    }
                    else if(ans > minn){
                        minn = ans;
                    }
                }
                st.push(j);
            }
        }
        cout << minn << endl;
    }
    return 0;
}

你可能感兴趣的:(ACM)