BZOJ 3039 玉蟾宫

Description

有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。
这片土地被分成N*M个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。
现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着'F'并且面积最大。
但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你S两银子。


Input

第一行两个整数N,M,表示矩形土地有N行M列。
接下来N行,每行M个用空格隔开的字符'F'或'R',描述了矩形土地。

Output

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

Sample Input

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

Sample Output

45

HINT



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

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

 

题意:给你一个0 1的矩阵,求最大的全是1的矩阵。

题解:枚举矩形下方的两个点(这个过程只需要枚举3个坐标),然后再找最大能够向上延伸多高。容易预处理出每个位置向上最多延伸多高,那么要求的就是这两个点直接所有点(包括这两个点)的延伸高度的最小值。

   对于区间最小值作贡献问题,一个常用的套路是枚举最小值,考虑贡献。那么可以使用单调栈(查询向左和向右第一个小于它的高度的值,向左向右维护一个单调递增的栈即可)处理出一个数左边第一个小于它的位置和右边第一个小于它的位置。这两个位置之间的都大于它,此时这个数作为最小值,最大宽度为位置差,直接计算贡献即可。O(n*m)
 
暴力(n^3) 不能过的
#include <bits/stdc++.h>

const int maxn=1005;
int n, m, a[maxn][maxn];

int main()
{
    char s[10];
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
        {
            scanf("%s", s);
            a[i][j]= s[0]=='F'? 1+a[i][j-1]:a[i][j-1];
        }
    int ans=0;
    for(int l=1; l<=m; l++)
        for(int r=l; r<=m; r++)
        {
            int tans=0;
            for(int i=1; i<=n; i++)
            {
                if(a[i][r]-a[i][l-1]==r-l+1) tans+=a[i][r]-a[i][l-1];
                else tans=0;
                ans=std::max(ans, tans);
            }
        }
    printf("%d\n", ans*3);
    return 0;
}
View Code
单调栈:
/**************************************************************
    Problem: 3039
    User: strangers
    Language: C++
    Result: Accepted
    Time:780 ms
    Memory:5244 kb
****************************************************************/
 
#include <bits/stdc++.h>
 
const int maxn=1005;
int n, m, a[maxn][maxn];
int ls[maxn], rs[maxn], stk[maxn], top;
 
void debug()
{
    for(int i=1; i<=m; i++)
        printf("ls[%d]=%d, rs[%d]=%d ", i, ls[i], i, rs[i]);
    printf("\n");
}
 
int main()
{
    char s[10];
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
        {
            scanf("%s", s);
            a[i][j]= s[0]=='F'? 1+a[i-1][j]:0;
        }
    int ans=0;
    for(int i=1; i<=n; i++)
    {
        top=0, stk[top]=0;
        for(int j=1; j<=m; j++)
        {
            while(top && a[i][stk[top]]>=a[i][j]) top--;
            ls[j]=stk[top], stk[++top]=j;
        }
        top=0, stk[top]=m+1;
        for(int j=m; j; j--)
        {
            while(top && a[i][stk[top]]>=a[i][j]) top--;
            rs[j]=stk[top], stk[++top]=j;
        }
        //debug();
        for(int j=1; j<=m; j++)
            ans=std::max(ans, a[i][j]*(rs[j]-ls[j]-1));
    }
    printf("%d\n", ans*3);
    return 0;
}
View Code
posted @ 2019-09-11 20:41  N_Yokel  阅读(137)  评论(0编辑  收藏  举报