P4147 玉蟾宫

题目背景

有一天,小猫 rainbow 和 freda 来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们

并赐予它们一片土地。
题目描述

这片土地被分成 \(N\times M\) 个格子,每个格子里写着 'R' 或者 'F',R 代表这块土地被赐予了 rainbow,

F 代表这块土地被赐予了 freda。现在 freda 要在这里卖萌。。。它要找一块矩形土地,

要求这片土地都标着 'F' 并且面积最大。但是 rainbow 和 freda 的 OI 水平都弱爆了,找不出这块土地,

而蓝兔也想看 freda 卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为 S,它们每人给你 S 两银子。

输入格式

第一行两个整数 N,M,表示矩形土地有 N 行 M 列。

接下来 N 行,每行 M 个用空格隔开的字符 'F' 或 'R',描述了矩形土地。

输出格式

输出一个整数,表示你能得到多少银子,即 (3\times \text{最大 'F' 矩形土地面积}) 的值。

输入输出样例

输入 #1

5 6
R F F F F F
F F F F F F
R R R F F F
F F F F F F
F F F F F F

输出 #1

45

说明/提示

对于 50% 的数据,1 <= N,M <= 200

对于 100%100%100% 的数据,1≤N,M≤1000

我们可以想到O(n^4)的暴力。

枚举每个矩形的左上角和右下角,然后算出每个矩形的贡献,

最后在对每个矩形的贡献取个max便是最后的答案

但这样只能过一半的数据,然后我们就要考虑优化。

我们可以对每个点求出他向下所能延伸的高度,也就是矩形的高。

那么怎么确定矩形的宽呢?

如果,我们能求出他所能向左和向右能延伸的长度,那么这个矩形的贡献不就很好的求出来了吗?

一个点能向左右两边延伸,当且仅当左右两边能向下延伸的高度比他大的时候。

我甩给你一张图:

颜色表示每个点能向下延伸的最大长度,看看这张图应该能明白吧(

自己可以手动模拟一下。

求序列中第一个比他小的数,那这不是单调栈吗?

所以,我们对每一行从左往右跑一边单调栈,在反过来跑一边就可以求出每个点的贡献

最后答案一定不要忘记乘三(当初我傻乎乎的调了半天才发现没乘三)

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
char ch; 
int n,m,top,ans;
int sta[1010],ls[1010],rs[1010],h[1010][1010];
inline int read()
{
	int s = 0, w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
	return s * w;
}
int main()
{
    n = read(); m = read();
    for(int i = 1; i <= n; i++)
    {
    	for(int j = 1; j <= m; j++)
    	{
    		cin>>ch;
    		if(ch == 'F') h[i][j] = h[i-1][j] + 1;//求出每个点能向下延伸的高度也就是矩形的高
    	}
    	top = 0; sta[++top] = 0;
    	for(int j = 1; j <= m; j++)//正着跑一遍单调栈求出每个点能向左延伸的长度
    	{
    		while(top && h[i][sta[top]] >= h[i][j]) top--;
    		ls[j] = sta[top]; sta[++top] = j; 
    	}
    	top = 0; sta[++top] = m+1;
    	for(int j = m; j >= 1; j--)//反着跑一遍单调栈求出每个点向右能延伸的长度
    	{
    		while(top && h[i][sta[top]] >= h[i][j]) top--;
    		rs[j] = sta[top]; sta[++top] = j;
    	}
    	for(int j = 1; j <= m; j++)
    	{
    		ans = max(ans,3 * h[i][j] * (rs[j]-ls[j]-1));//统计答案
    	}
    }
	printf("%d\n",ans);
	return 0;
}

听别的大佬用悬线法切了这道题。

但蒟蒻我太菜了,没学会。

先占上坑吧,后期再补。

ENDING

posted @ 2020-08-15 19:13  genshy  阅读(157)  评论(0编辑  收藏  举报