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  阅读(77)  评论(0编辑  收藏