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 数组是一样的处理方式.
然后每一次的以当前我们的高度处理出来的最大面积就是:

\[height[i]×(R[i]-L[i]+1) \]

然后统计答案即可.


然后这道题题目就用这个模板处理出来每一行即可.

代码

#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;
}
posted @ 2018-06-10 22:16  Kevin_naticl  阅读(473)  评论(0编辑  收藏  举报