当前位置:首页 > 洛谷题解 > 洛谷P3400题解:单调栈统计全1子矩阵的巧妙方法

洛谷P3400题解:单调栈统计全1子矩阵的巧妙方法

1天前洛谷题解43

截图未命名.jpg 洛谷P3400题解:单调栈统计全1子矩阵的巧妙方法 单调栈 柱状图 矩阵统计 高精度 洛谷题解 第1张

一、问题描述

给定一个由0和1组成的n×m矩阵,要求统计所有全1子矩阵的数量。这个问题可以转化为对每个位置计算以其为右下角的子矩阵数量。

二、算法核心思想

  1. 高度数组预处理:将问题转化为柱状图问题

  2. 单调栈应用:高效计算每个位置的左右边界

  3. 组合数学计算:利用边界信息统计子矩阵数量

三、完整代码实现(带详细注释)

#include <iostream>
#include <stack>
#include <vector>
using namespace std;

const int MAXN = 3005;
int h[MAXN][MAXN]; // 高度数组,记录每个位置向上连续1的个数
int n, m;

// 计算单行中的全1子矩阵数
long long solveRow(int row) {
    stack<int> st;
    long long res = 0;
    vector<int> left(m+2), right(m+2);
    
    // 左边界计算:找到每个位置左边第一个比它小的位置
    for(int j = 1; j <= m; j++) {
        while(!st.empty() && h[row][st.top()] >= h[row][j]) {
            st.pop();
        }
        left[j] = st.empty() ? 0 : st.top();
        st.push(j);
    }
    
    // 清空
    while(!st.empty()) st.pop();
    
    // 右边界计算:找到每个位置右边第一个比它小的位置
    for(int j = m; j >= 1; j--) {
        while(!st.empty() && h[row][st.top()] > h[row][j]) {
            st.pop();
        }
        right[j] = st.empty() ? m+1 : st.top();
        st.push(j);
    }
    
    // 计算结果:以当前位置为最高点的子矩阵数量
    for(int j = 1; j <= m; j++) {
        if(h[row][j] == 0) continue;
        res += (long long)(j - left[j]) * (right[j] - j) * h[row][j];
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> m;
    long long ans = 0;
    
    // 预处理高度数组:计算每个位置向上连续1的个数
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            char c; cin >> c;
            if(c == '1') h[i][j] = h[i-1][j] + 1;
            else h[i][j] = 0;
        }
    }
    
    // 逐行计算:对每一行应用单调栈算法
    for(int i = 1; i <= n; i++) {
        ans += solveRow(i);
    }
    
    cout << ans << endl;
    return 0;
}

四、算法分步解析

  1. 高度数组预处理

    • 计算每个位置向上连续1的个数

    • 将二维问题转化为一维柱状问题

  2. 单调栈操作

    • 左边界计算:找到每个位置左边第一个比它小的位置

    • 右边界计算:找到每个位置右边第一个比它小的位置

    • 使用栈维护单调递增序列

  3. 结果计算

    • 对每个非零高度位置,计算以其为最高点的子矩阵数量

    • 公式:(当前位置-左边界)×(右边界-当前位置)×高度

五、扩展思考

  1. 如何优化算法处理更大的矩阵?

  2. 如果要求统计特定形状的子矩阵该如何修改?

  3. 这个问题与最大全1子矩阵问题有什么联系?

  4. 如何扩展到三维情况?


原创内容 转载请注明出处

分享给朋友:

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。