# 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编辑  收藏