BZOJ1057(单调栈 or 悬线法)

方法一

  • 黑白棋盘拥有性质:(r + c) % 2的值决定颜色
  • 因此把某色全部反转,直接求另一色的最大矩形即可,单调栈的经典问题
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn = 2005;
int n, m, a[maxn][maxn], h[maxn][maxn];
int ans1, ans2;

void solve(int c) {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            h[i][j] = (a[i][j] == c) ? h[i][j - 1] + 1 : 0;
        }
    }
    int L[n + 5], R[n + 5];
    for (int j = 1; j <= m; j++) {
        vector<int> st;
        for (int i = 1; i <= n; i++) {
            while (st.size() && h[st.back()][j] >= h[i][j]) st.pop_back();
            L[i] = st.size() ? st.back() + 1 : 1;
            st.emplace_back(i);
        }
        st.clear();
        for (int i = n; i; i--) {
            while (st.size() && h[st.back()][j] >= h[i][j]) st.pop_back();
            R[i] = st.size() ? st.back() - 1 : n;
            st.emplace_back(i);
        }
        for (int i = 1; i <= n; i++) {
            int S = h[i][j] * (R[i] - L[i] + 1);
            int t = min(h[i][j], R[i] - L[i] + 1);
            ans1 = max(ans1, t * t);
            ans2 = max(ans2, S);
        }
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            scanf("%d", &a[i][j]);
            if ((i + j) & 1)
                a[i][j] ^= 1;
        }
    solve(0), solve(1);
    return !printf("%d\n%d\n", ans1, ans2);
}

方法二

  • 悬线法:对每个点求出它合法的矩阵向左向右向上分别能多长,然后更新答案。其中求时肯定不能暴力,要从上一个递推过来
  • 如果高度能从上面递增过来,左右线也要跟上面取min
  • 其实我觉得和方法一思想挺像的……
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 2005;
int n, m, a[maxn][maxn];
int h[maxn][maxn], l[maxn][maxn], r[maxn][maxn];
int ans1, ans2;

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            scanf("%d", &a[i][j]);

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (i > 1 && a[i][j] != a[i][j - 1]) {
                l[i][j] = l[i][j - 1] + 1;
            } else  l[i][j] = 1;
        }
        for (int j = m; j; --j) {
            if (j < m && a[i][j] != a[i][j + 1]) {
                r[i][j] = r[i][j + 1] + 1;
            } else  r[i][j] = 1;
        }
        for (int j = 1; j <= m; j++) {
            if (i > 1 && a[i][j] != a[i - 1][j]) {
                h[i][j] = h[i - 1][j] + 1;
                l[i][j] = min(l[i][j], l[i - 1][j]);
                r[i][j] = min(r[i][j], r[i - 1][j]);
            } else  h[i][j] = 1;

            int Len = r[i][j] + l[i][j] - 1;
            int t = min(Len, h[i][j]);
            ans1 = max(ans1, t * t);
            ans2 = max(ans2, Len * h[i][j]);
        }
    }
    return !printf("%d\n%d\n", ans1, ans2);
}
posted @ 2019-06-10 14:47  AlphaWA  阅读(...)  评论(... 编辑 收藏