P4147 玉蟾宫 (单调栈)
题目背景
有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。
题目描述
这片土地被分成N*M个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。
现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着'F'并且面积最大。
但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你S两银子。
输入输出格式
输入格式:
第一行两个整数N,M,表示矩形土地有N行M列。
接下来N行,每行M个用空格隔开的字符'F'或'R',描述了矩形土地。
输出格式:
输出一个整数,表示你能得到多少银子,即(3*最大'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%的数据,1<=N,M<=1000
Solution
模板最大子矩阵...
这道题需要用到一个东西,叫做单调栈.于是乎就在这里做一个补充.
首先,我们需要将这个问题转换一下:
图中是一个 4×6 的矩形,画出红色的是我们要找到的区域。
然后我们可以将这个图转化:
因为我们要找的是矩形,所以它一定是以 某个行元素开始的,如果枚举行的时候,我们会发现:
对于第一行:
对于第二行:
第三行:
第四行:
那么我们原始矩形可以变成如下的形式的数据:
然后此时的话,就是给你若干个柱状图,然后要你求其中的最大矩形: ![](https://images2018.cnblogs.com/blog/1277344/201806/1277344-20180610221715632-461351500.gif)
那么明显是可以 n^2 枚举的,但是这样会爆.
那么怎样才能在 O(n) 的时间复杂度下处理出这个东西呢?
我们使用单调栈.
单调栈,顾名思义,就是里面元素满足单调性质的一个栈.因为我们可以很容易推出来,当我们一个矩形的高度可以计算的时候,选择的区域里面所有条状的高度都要大于等于当前这个高度.
然后我们看具体操作:
一个 L 数组 ,代表当前这个高度,我们可以达到的最左边的点.
一个 R 数组 ,同理.
我们需要遍历两遍,一遍处理当前的 L 数组.一遍处理 R 数组.
1)先将一个 (0,0) 的元素推进栈中.
2)每一次我们遍历到的点就是我们现在要处理的.
3)先一直把栈中高于当前选择的节点的高度的点都弹出.
(这个应该很好理解.因为只有低于我的点才是边界).
4)如果栈已经空了,就把 L [ i ] 赋成 1.
5)否则,则赋成当前的栈顶+1 (栈顶已经小于我们了).
然后的话 R 数组是一样的处理方式.
然后每一次的以当前我们的高度处理出来的最大面积就是:
然后统计答案即可.
然后这道题题目就用这个模板处理出来每一行即可.
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1008;
int c[maxn][maxn];
int n,m,ans=-1;
int a[maxn][maxn];
int pre(int x,int y)
{
if(x>n)return 0;
if(c[x][y]==1)a[x][y]=1;
pre(x+1,y);
if(a[x][y])
a[x][y]+=a[x+1][y];
return a[x][y];
}
void getans(int x)
{
stack<int>s;
int l[maxn]={0},r[maxn]={0};
for(int i=1;i<=m;i++)
{
while(s.size()&&a[x][s.top()]>=a[x][i])
s.pop();
if(s.empty()) l[i]=1;
else l[i]=s.top()+1;
s.push(i);
}
while(!s.empty()) s.pop();
for(int i=m;i>=1;i--)
{
while(s.size()&&a[x][s.top()]>=a[x][i])
s.pop();
if(s.empty())
r[i]=m;
else
r[i]=s.top()-1;
s.push(i);
}
while(!s.empty()) s.pop();
for(int i=1;i<=m;i++)
{
int num=a[x][i]*(r[i]-l[i]+1);
ans=max(num,ans);
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
char ch;
cin>>ch;
if(ch=='R')c[i][j]=0;
else c[i][j]=1;
}
for(int i=1;i<=m;i++)
pre(1,i);
for(int i=1;i<=n;i++)
getans(i);
cout<<ans*3<<endl;
return 0;
}