BZOJ 1057. [ZJOI2007]棋盘制作
根据奇偶性,把x,y坐标加起来是奇数的位置翻转一下,就变成求最大01子矩阵了。
然后预处理出每个位置往上最长的01路径,每行用一个单调栈解决。
单调栈从栈底到栈顶维护每一个矩阵的高度和宽度,按高度递增维护。
当前高度如果小于栈顶的高度,那就将栈顶的矩阵更新答案,并且出栈,但是它的宽度是可以为当前高度的矩阵做贡献的,就是当前要加入栈的矩阵的宽度得加上这个要出栈的矩阵。
最后一列做完之后再清一下栈就行了。
#include <bits/stdc++.h> #define pii pair<int, int> #define fi first #define se second const int N = 2222; int a[N][N], dp[N][N], n, m, ans1, ans2; std::pii st[N]; void solve() { for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) dp[i][j] = (a[i][j] ? dp[i - 1][j] + 1 : 0); for (int i = 1; i <= n; i++) { int top = 0; for (int j = 1; j <= m + 1; j++) { int w = 0; while (top && st[top].fi > dp[i][j]) { int h = st[top].fi; w += st[top].se; top--; ans1 = std::max(ans1, std::min(w, h) * std::min(w, h)); ans2 = std::max(ans2, w * h); } st[++top] = std::pii(dp[i][j], w + 1); } } } 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) % 2) a[i][j] ^= 1; } solve(); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) a[i][j] ^= 1; solve(); printf("%d\n%d\n", ans1, ans2); return 0; }