题解:P10965 Largest Submatrix

· · 题解

题目链接

https://www.luogu.com.cn/problem/P10965

分析

和 P4147 玉蟾宫 一题很像。

易于想到,给定矩阵最大的全部元素都相同的子矩阵的元素个数最多时,矩阵中一定只存在 abc。分别处理使 abc 数量最多时的情况。

那么对于矩阵中的每一个位置,可以分别求出从当前位置向上全为相同字母的最大高度,记为 maxheight_i。处理完一行的高度后,还可以用单调栈求出每个位置左侧和右侧第一个高度小于当前高度的位置,记作 posl_i, posr_i

那么就可以形成从 posl_i + 1posr_i - 1,高度为 maxheight_i 的矩阵,即贡献为 (posr_i - posl_i + 1) \times maxheight_i

在所有位置的贡献中取最大值即为答案。

细节内容见代码注释。

Code

#include <bits/stdc++.h>

using namespace std;

constexpr int N = 1005;
int n, m, pos_l[N], pos_r[N], max_ht[N][N][3]; char mp[N][N];

deque<int> que;

int main()
{
//  freopen(".in", "r", stdin), freopen(".out", "w", stdout);

    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

    for (; cin >> n >> m; )
    {
        for (int i = 1; i <= n; ++ i) cin >> mp[i] + 1;

        memset(max_ht, 0, sizeof max_ht); // 多测清空
        for (int i = 1; i <= n; ++ i) for (int j = 1; j <= m; ++ j) switch(mp[i][j])
        {
            // 分别处理每种情况,'a' -> 0,'b' -> 1,'c' -> 2
            case 'a': { max_ht[i][j][0] = 1 + max_ht[i - 1][j][0]; break; }
            case 'b': { max_ht[i][j][1] = 1 + max_ht[i - 1][j][1]; break; }
            case 'c': { max_ht[i][j][2] = 1 + max_ht[i - 1][j][2]; break; }
            case 'w': { max_ht[i][j][0] = 1 + max_ht[i - 1][j][0], max_ht[i][j][1] = 1 + max_ht[i - 1][j][1]; break; }
            case 'x': { max_ht[i][j][1] = 1 + max_ht[i - 1][j][1], max_ht[i][j][2] = 1 + max_ht[i - 1][j][2]; break; }
            case 'y': { max_ht[i][j][0] = 1 + max_ht[i - 1][j][0], max_ht[i][j][2] = 1 + max_ht[i - 1][j][2]; break; }
            case 'z': { max_ht[i][j][0] = 1 + max_ht[i - 1][j][0], max_ht[i][j][1] = 1 + max_ht[i - 1][j][1], max_ht[i][j][2] = 1 + max_ht[i - 1][j][2]; break; }
        }

        int ans = 0;
        for (int num = 0; num < 3; ++ num) for (int i = 1; i <= n; ++ i)
        {
            // 单调栈处理右侧
            max_ht[i][m + 1][num] = -1;
            for (int j = 1; j <= m + 1; ++ j)
            {
                for (; !que.empty() && max_ht[i][j][num] < max_ht[i][que.back()][num]; pos_r[que.back()] = j, que.pop_back());
                que.push_back(j);
            }

            // 单调栈处理左侧
            max_ht[i][0][num] = -1;
            for (int j = m; 0 <= j; -- j)
            {
                for (; !que.empty() && max_ht[i][j][num] < max_ht[i][que.back()][num]; pos_l[que.back()] = j, que.pop_back());
                que.push_back(j);
            }

            // 计算贡献
            for (int j = 1; j <= m; ++ j) ans = max(ans, max_ht[i][j][num] * (pos_r[j] - pos_l[j] - 1));
        }

        cout << ans << '\n';
    }
    return 0;
}