A City Game题解

题目链接:https://vjudge.net/problem/UVA-1330
题目大意:给出一个n*m的矩阵,求这个矩阵中全是F的矩形的最大面积是多少。
题目分析:枚举每一行,判断以这一行为矩形的底所能得到的矩形的最大面积为多少,问题就转换为典型的单调栈问题。
对每个矩形条而言,若以它的高度为整个矩形的高,那么矩形的宽就为右边第一个高度比它小的矩形的坐标 - 左边第一个比它小的坐标 - 1
在一个序列中找一个数左边(或右边)第一个比它小的数可以使用单调栈分数据结构。
以求左边第一个比它小的数为例:具体来讲就是维护一个栈,这个栈从栈底到栈顶的元素都是单调递增的,每当插入一个元素,要维持单调的性质,就要和栈顶的元素比较,如果栈顶的元素比它大,就把它弹出栈。(因为比它大的元素在找之后的元素的左边第一个比它小的元素的时候,都会被新插入的元素限制,即比那些比新插入的元素大的元大的元素也一定比新插入的元素大,所以那些元素再之后永远不会成为答案,所以可以直接去掉(及时去除冗余的思想))。第一个比它小的左边的元素就是单调栈的栈顶。由于每个元素入栈一次,最多出栈一次,时间复杂度为线性的。由于在此题中要求的是矩形的宽而不是,第一个比它低的矩形的高,所以单调栈可以直接维护矩形的位置而不是高度,这样更方便一点。另外可以通过递推求得每个矩形的高。
代码如下:

# include <iostream>
# include <cstdio>
# include <cmath>
# include <algorithm>
# include <stack>
# include <cstring>

using namespace std;
const int N = 1005;
const int M = 1005;

int T, n, m, ans, dp[N][M], l[M], r[M];
char s[N][M];

int main() {
	cin >> T;
	while (T--) {
		ans = 0;
		memset(dp, 0, sizeof(dp));
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				cin >> s[i][j];
				if (s[i][j] == 'F') dp[i][j] = dp[i - 1][j] + 1;
			}
		}
		for (int i = 1; i <= n; i++) {
			stack<int> sta;
			for (int j = 1; j <= m; j++) {
				while (!sta.empty() && dp[i][sta.top()] >= dp[i][j]) sta.pop();
				if (sta.empty()) l[j] = 0;
				else l[j] = sta.top();
				sta.push(j);
			}
			while (!sta.empty()) sta.pop();
			for (int j = m; j >= 1; j--) {
				while (!sta.empty() && dp[i][sta.top()] >= dp[i][j]) sta.pop();
				if (sta.empty()) r[j] = m + 1;
				else r[j] = sta.top();
				sta.push(j);
			}
			for (int j = 1; j <= m; j++)
				ans = max(ans, dp[i][j] * (r[j] - l[j] - 1));
		}
		cout << ans * 3 << endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值