【题目链接】
参考了【wuyuhan的题解】
记m = ∑wi
对于n <= 300的情况,暴力O(n^2)枚举矩形的上下边界,O(m)计算矩形内的答案。
对于n > 300的情况,暴力O(n)枚举矩形的上边界,然后枚举暴力O(m)枚举高度(最大全0子矩阵单调栈做法的高度),最后对于每个高度,O(m)计算矩形内的答案。
计算答案的过程是:
枚举每一个矩形,计算出所有矩形左边界和右边界能向内延伸的最大值和次大值,记录次大值的原因是,如果左边界右边界最大值的矩形是同一个矩形,那么就不合法了,就只能用次大值去更新答案。
/* Telekinetic Forest Guard */ #include <cstdio> #include <cstring> #include <algorithm> #include <bitset> using namespace std; const int maxn = 305, maxm = 100005; int s, n, m, pos[maxm]; bitset<maxm> g[maxn], mp; inline int iread() { int f = 1, x = 0; char ch = getchar(); for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return f * x; } inline int cread() { char ch = getchar(); for(; ch != '0' && ch != '1'; ch = getchar()); return ch - '0'; } namespace subtask1 { void solve() { int ans = 0; for(int i = 1; i <= s; i++) { pos[i] = pos[i - 1] + iread(); for(int j = 1; j <= n; j++) for(int k = pos[i - 1] + 1; k <= pos[i]; k++) g[j][k] = cread(); } m = pos[s]; for(int i = 1; i <= n; i++) { mp = g[i]; for(int j = i; j <= n; j++) { mp |= g[j]; for(int k = 1, sum = 0; k <= m; k++) { sum = mp[k] ? 0 : sum + 1; ans = max(ans, sum * (j - i + 1)); } int l1 = 0, l2 = 0, lno = 0; int r1 = 0, r2 = 0, rno = 0; int sum = 0, full = 0; for(int k = 1; k <= s; k++) { sum = 0; for(int l = pos[k - 1] + 1; l <= pos[k]; l++, sum++) if(mp[l]) break; if(sum == pos[k] - pos[k - 1]) { full += sum; continue; } if(sum > l1) l2 = l1, l1 = sum, lno = k; else if(sum > l2) l2 = sum; sum = 0; for(int r = pos[k]; r >= pos[k - 1] + 1; r--, sum++) if(mp[r]) break; if(sum > r1) r2 = r1, r1 = sum, rno = k; else if(sum > r2) r2 = sum; } ans = max(ans, (((lno == rno) ? max(l1 + r2, l2 + r1) : l1 + r1) + full) * (j - i + 1)); } } printf("%d\n", ans); } } namespace subtask2 { int f[maxm]; void solve() { int ans = 0; for(int i = 1; i <= s; i++) { pos[i] = pos[i - 1] + iread(); for(int k = 1; k <= n; k++) for(int j = pos[i - 1] + 1; j <= pos[i]; j++) g[j][k] = cread(); } m = pos[s]; for(int i = n; i; i--) { for(int j = 1; j <= m; j++) f[j] = g[j][i] ? 0 : f[j] + 1; for(int j = 1; j <= m; j++) { for(int k = 1, sum = 0; k <= m; k++) { sum = f[k] < f[j] ? 0 : sum + 1; ans = max(ans, f[j] * sum); } int l1 = 0, l2 = 0, lno = 0; int r1 = 0, r2 = 0, rno = 0; int sum = 0, full = 0; for(int k = 1; k <= s; k++) { sum = 0; for(int l = pos[k - 1] + 1; l <= pos[k]; l++, sum++) if(f[l] < f[j]) break; if(sum == pos[k] - pos[k - 1]) { full += sum; continue; } if(sum > l1) l2 = l1, l1 = sum, lno = k; else if(sum > l2) l2 = sum; sum = 0; for(int r = pos[k]; r >= pos[k - 1] + 1; r--, sum++) if(f[r] < f[j]) break; if(sum > r1) r2 = r1, r1 = sum, rno = k; else if(sum > r2) r2 = sum; } ans = max(ans, (((lno == rno ? max(l1 + r2, l2 + r1) : l1 + r1) + full) * f[j])); } } printf("%d\n", ans); } } int main() { freopen("puzzle.in", "r", stdin); freopen("puzzle.out", "w", stdout); for(int T = iread(); T; T--) { s = iread(), n = iread(); if(n <= 300) subtask1::solve(); else subtask2::solve(); } return 0; }