玉蟾宫
题目来源:https://www.luogu.com.cn/problem/P4147
题目背景
有一天,小猫 rainbow 和 freda 来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。
题目描述
这片土地被分成 N × M N\times M N×M 个格子,每个格子里写着 ‘R’ 或者 ‘F’,R 代表这块土地被赐予了 rainbow,F 代表这块土地被赐予了 freda。
现在 freda 要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着 ‘F’ 并且面积最大。
但是 rainbow 和 freda 的 OI 水平都弱爆了,找不出这块土地,而蓝兔也想看 freda 卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为 S S S,它们每人给你 S S S 两银子。
输入格式
第一行两个整数 N N N, M M M,表示矩形土地有 N N N 行 M M M 列。
接下来 N N N 行,每行 M M M 个用空格隔开的字符 ‘F’ 或 ‘R’,描述了矩形土地。
输出格式
输出一个整数,表示你能得到多少银子,即 ( 3 × 最大 ’F’ 矩形土地面积 3\times \text{最大 'F' 矩形土地面积} 3×最大 ’F’ 矩形土地面积) 的值。
样例 #1
样例输入 #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
%
50\%
50% 的数据,
1
≤
N
,
M
≤
200
1 \leq N, M \leq 200
1≤N,M≤200。
对于
100
%
100\%
100% 的数据,
1
≤
N
,
M
≤
1000
1 \leq N, M \leq 1000
1≤N,M≤1000。
思路分析
这道题和求最大子矩阵非常像,其中,二维贡献法适用于二维矩阵,且给定一些障碍物,然后求子矩阵的面积/价值等最大值的问题,因此,这道题就是用此方法实现,我们只要处理上、左、右即可,如果是一维的贡献法,拓展:一维贡献法也是适用于求子序列的价值/单独出现的最大值,具体可以见 孤独的照片,说到这里,回归正题,二维贡献法如何实现?我们可以用数组来存储左、右、上能扩展到的最大距离,然后我们每次只处理每一行,然后对每一行求出左、上、右能扩展到的最大距离,最后求最大面积只需max(res,h[i][j]*(r[i][j]-l[i][j]+1))
,这样就可以得到答案了。
以下就是板子题
代码(模板)
//悬线法适用于在一个矩形内,而且有障碍物的情况下,求最大的子矩形面积
//悬线法只要处理上、左、右之间的关系,因为我们直接设了一行
//本人感觉悬线法和贡献法有点类似,只不过扩展成二维了
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
char str[N][N];
int l[N][N],r[N][N];//左、右
int h[N][N];//高度
int n,m;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>str[i][j];
if(str[i][j]=='F')h[i][j]=1;
l[i][j]=r[i][j]=j;//最远到达的位置
}
}
for(int i=1;i<=n;i++){//处理每一行的左、右
for(int j=2;j<=m;j++){
if(str[i][j]=='F'&&str[i][j-1]=='F'){//处理左
l[i][j]=l[i][j-1];
}
}
for(int j=m-1;j>=1;j--){
if(str[i][j]=='F'&&str[i][j+1]=='F'){//处理右
r[i][j]=r[i][j+1];
}
}
}
//处理上
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(str[i][j]=='F'&&str[i-1][j]=='F'){
h[i][j]=h[i-1][j]+1;
r[i][j]=min(r[i][j],r[i-1][j]);//也要看上面能到哪里
l[i][j]=max(l[i][j],l[i-1][j]);
}
if(str[i][j]=='F')res=max(res,h[i][j]*(r[i][j]-l[i][j]+1));
}
}
cout<<res*3;
return 0;
}