思路:单调栈
其实这个需要转化一下问题,我们看到,这里让我们求最大矩形面积,并且里面会有被破坏的点。
暴力的话,我们肯定想到枚举上下边界,左右边界,然后判断里面的方格的状态是不是被破坏的,但是这样的循环复杂度会很大,所以我们需要想着优化才行。
那么,你可能会想到单调队列,因为这也是可以让时间复杂度变得简单的方法之一。但是不行,因为这里有妨碍点,也就是被破坏的点并不能讨论在内,况且我们需要连续的点,所以我们需要借助单调栈。
代码模拟:定义一个二维数组h,代表在每一行里面的最大高度,第二维其实就是不断地枚举地图的点,判断是不是有妨碍点,然后再取值的一个工具,并不是真的一列一列的枚举,而是每一行枚举每一列的一次,同时对每一列的高度进行更新的,这里需要大家细品,也就相当于是一个直方图的统计表一样。
我们取到了每一列的最大高度h[i],那么我们就会想到,这里矩形的长度该怎么办?
其实不难发现,如果是一个矩形,那么两个边界必须是相同的,并且高度一致。既然我们已经确定了高度了,只需要枚举每一列中的高度,求出来连续相同的高度最大值,然后乘以长度就行了。
这就要求这个矩形的两边的边界的旁边都必须是小于这个高度的,因为这样才能显出来这个矩形是最大面积,要是旁边两个边界的高度都是大于这个矩阵的高度,那么我们还真不能这样取最大值,因为还有更大的高度供我们选择。这里就要求我们用单调栈进行实现这个操作了。
上代码:
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<deque>
#include <iomanip>
#include<sstream>
#include<numeric>
#include<map>
#include<limits.h>
#include<unordered_map>
#include<set>
#define int long long
#define MAX 3010
#define inf 0x3f3f3f3f
#define _for(i,a,b) for(int i=a;i<(b);i++)
using namespace std;
typedef pair<int, int> PII;
int n, m,k;
int counts;
int dx[] = { 0,1,0,-1};
int dy[] = { 1,0,-1,0 };
int h[MAX][MAX];
int st[MAX][MAX],top;
int stk[MAX];//stack
int l[MAX], r[MAX];
int solve(int h[]) {
top = 0;
h[0] = -1;
h[m + 1] = -1;
stk[++top] = 0;
_for(i, 1, m + 1) {
while (h[stk[top]] >= h[i])top--;
l[i] = stk[top];
stk[++top] = i;
}
top = 0;
stk[++top] = m + 1;
for (int i = m; i;i--) {
while (h[stk[top]] >= h[i])top--;
r[i] = stk[top];
stk[++top] = i;
}
int res = 0;
_for(i, 1, m + 1) {
res = max(res, h[i] * (r[i] - l[i] - 1));
}
return res;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> n >> m >> k;
while (k--) {
int x, y;
cin >> x >> y;
st[x][y] = 1;
}
_for(i, 1, n + 1) {
_for(j, 1, m + 1) {
if (!st[i][j]) {
h[i][j] = h[i - 1][j] + 1;
}
}
}
int res = 0;
_for(i, 1, n + 1) {
res = max(res, solve(h[i]));
}
cout << res;
return 0;
}