SP277 CTGAME - City Game 题解

题目传送门

前置知识

单调栈

解法

\(f_{i,j}(1 \le i \le n,1 \le j \le m)\) 表示从 \((1,j)\)\((i,j)\) 中以 \((i,j)\) 结尾的均为 F 的子串长度,即 \((i,j)\) 上面可延伸的最大距离(子矩形的长)。

用单调栈的第一维存储子矩形的长,第二维存储子矩形的宽。考虑依次枚举每一行和每一列,进行出入栈的操作。当枚举到 \((i,j)\) 的位置时,记录子矩形的宽 \(num\),有如下操作:

  • 对于栈中原来的元素中大于当前的长 \(f_{i,j}\),要将其弹出栈,计数器 \(num\)\(1\)
    • 子矩形的宽为弹出栈的元素个数。
    • 其所形成的子矩形面积为 $num \times $ 栈中当前的元素。
  • 将所得到的长 \(f_{i,j}\) 和宽 \(num\) 入栈。

代码

#include<bits/stdc++.h>
using namespace std;
int f[1001][1001];
int main()
{
    int n,m,t,v,i,j,ans,num;
    char pd;
    cin>>t;
    for(v=1;v<=t;v++)
    {
        ans=0;
        cin>>n>>m;
        memset(f,0,sizeof(f));
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
            {
                cin>>pd;
                if(pd=='F')
                {
                    f[i][j]=f[i-1][j]+1;
                }
            }
        }
        for(i=1;i<=n;i++)
        {
            stack<pair<int,int>> s;
            s.push(make_pair(f[i][1],1));
            for(j=2;j<=m;j++)
            {
                num=0;
                while(s.empty()==0&&s.top().first>=f[i][j])
                {
                    num+=s.top().second;
                    ans=max(ans,num*s.top().first);
                    s.pop();
                }
                s.push(make_pair(f[i][j],num+1));
            }
            num=0;
            while(s.empty()==0)
            {
                num+=s.top().second;
                ans=max(ans,num*s.top().first);
                s.pop();
            }
        }
        cout<<ans*3<<endl;
    }
    return 0;
}

后记

多倍经验:P4147 | P5943 | UVA1330

posted @ 2024-02-07 21:02  hzoi_Shadow  阅读(5)  评论(0编辑  收藏  举报
扩大
缩小