「题解」洛谷 P1169 [ZJOI2007]棋盘制作

题目

P1169 [ZJOI2007]棋盘制作

简化题意

找到给出的矩阵中最大的 \(0,1\) 交替的矩形和正方形。

思路

单调栈,悬线法。

对每个点求出最多向上扩展多少,就变成了直方图最大矩形问题,对于正方形只要宽度和当前高取个最小值就行。

Code

悬线法:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 2001

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int n, m, map[M][M], up[M][M];
int maxj, maxz, l[M], r[M];

bool okayl(int c, int d) {
    if (up[c][d] <= up[c][l[d] - 1] && map[c][l[d]] != map[c][l[d] - 1]) return true;
    return false;
}

bool okayr(int c, int d) {
    if (up[c][d] <= up[c][r[d] + 1] && map[c][r[d]] != map[c][r[d] + 1]) return true;
    return false;
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            scanf("%d", &map[i][j]);
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (map[i][j] == map[i - 1][j]) up[i][j] = 1;
            else up[i][j] = up[i - 1][j] + 1;
            l[j] = r[j] = j;
        }
        for (int j = 1; j <= m; ++j) {
            while (l[j] > 1 && okayl(i, j)) l[j] = l[l[j] - 1];
        }
        for (int j = m; j >= 1; --j) {
            while (r[j] < m && okayr(i, j)) r[j] = r[r[j] + 1];
        }
        for (int j = 1; j <= m; ++j) {
            maxj = max(maxj, up[i][j] * (r[j] - l[j] + 1));
            int len = min(up[i][j], r[j] - l[j] + 1);
            maxz = max(maxz, len * len);
        }
    }
    std::cout << maxz << '\n' << maxj << '\n';
    return 0;
}

单调栈:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 2002

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

int n, m, map[M][M], up[M][M];
int ansj, ansz, top, s[M], w[M];

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            scanf("%d", &map[i][j]);
            if (map[i][j] == map[i - 1][j]) up[i][j] = 1;
            else up[i][j] = up[i - 1][j] + 1;
        }
    }
    for (int i = 1; i <= n; ++i) {
        top = 0;
        s[++top] = 1, w[top] = 1;
        map[i][m + 1] = map[i][m];
        for (int j = 2; j <= m + 1; ++j) {
            if (up[i][s[top]] < up[i][j] && map[i][j] != map[i][s[top]]) {
                s[++top] = j;
                w[top] = 1;
            }
            else {
                int len = 0;
                if (map[i][j] == map[i][s[top]]) {
                    while (top) {
                        len += w[top];
                        int l = min(len, up[i][s[top]]);
                        ansj = max(ansj, len * up[i][s[top]]);
                        ansz = max(ansz, l * l);
                        --top;
                    }
                    s[++top] = j, w[top] = 1;
                }
                else {
                    while (top && up[i][s[top]] >= up[i][j]) {
                        len += w[top];
                        int l = min(len, up[i][s[top]]);
                        ansj = max(ansj, len * up[i][s[top]]);
                        ansz = max(ansz, l * l);
                        --top;
                    }
                    s[++top] = j, w[top] = len + 1;
                }
            }
        }
    }
    std::cout << ansz << '\n' << ansj << '\n';
    return 0;
}
posted @ 2020-09-11 10:49  yu__xuan  阅读(140)  评论(0编辑  收藏  举报