跳到主要内容

P4147 玉蟾宫

题目背景

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

题目描述

这片土地被分成 N×MN\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×最大 ’F’ 矩形土地面积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% 的数据,1N,M2001 \leq N, M \leq 200。 对于 100% 的数据,1N,M10001 \leq N, M \leq 1000

题目分析

可发现题目要我们求的是满足条件的最大子矩阵。这类问题可以采用悬线法进行处理。

需要满足的条件则是区域由F组成。

up[x][y] 为从(x,y)(x,y) 位置向上符合条件的最长线段长度,即悬线长度。

L[x][y]为从(x,y)(x,y) 位置向左,悬线能平移的最长距离。

R[x][y]为从(x,y)(x,y) 位置向右,悬线能平移的最长距离。

子矩阵面积为up[x][y](L[x][y]+R[x][y]1)up[x][y]*(L[x][y]+R[x][y]-1)

当利用悬线法求出最大子矩阵面积后,将面积乘3即最终答案。

代码实现

#include <iostream>
#include <cstdio>
using namespace std;
const int N=1e3+5;
int up[N][N],L[N][N],R[N][N];
/*
up[x][y] 从(x,y)开始,向上连续F的最大长度
L[x][y] 从(x,y)开始,向左连续F的最大长度
R[x][y] 从(x,y)开始,向右连续F的最大长度
*/
int a[N][N];
int n,m;
int main(){
char c;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c;
a[i][j]=(c=='F')?1:0;
if(a[i][j]){//当(x,y)满足条件
up[i][j]=up[i-1][j]+1;//更新悬线
L[i][j]=L[i][j-1]+1;//更新从(i,j)向左的满足条件的最长长度
}
}
for(int j=m;j>=1;j--){
if(a[i][j]) R[i][j]=R[i][j+1]+1;//更新从(i,j)向右的满足条件的最长长度
}
}
/*
更新 L[][] 和 R[][] 为 从(x,y)想左/右的最大悬线平移距离
L[i][j]=min(L[i][j],L[i-1][j])
R[i][j]=min(R[i][j],LR[i-1][j])
*/
int maxs=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i>=2&&a[i][j]&&a[i-1][j]){
L[i][j]=min(L[i][j],L[i-1][j]);
R[i][j]=min(R[i][j],R[i-1][j]);
}
maxs=max(maxs,up[i][j]*(L[i][j]+R[i][j]-1));//更新最大子矩阵面积
}
}
cout<<3*maxs;
return 0;
}