悬线法(二维贡献法)——玉蟾宫

玉蟾宫

题目来源: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 1N,M200
对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 1000 1 \leq N, M \leq 1000 1N,M1000

思路分析

这道题和求最大子矩阵非常像,其中,二维贡献法适用于二维矩阵,且给定一些障碍物,然后求子矩阵的面积/价值等最大值的问题,因此,这道题就是用此方法实现,我们只要处理上、左、右即可,如果是一维的贡献法,拓展:一维贡献法也是适用于求子序列的价值/单独出现的最大值,具体可以见 孤独的照片,说到这里,回归正题,二维贡献法如何实现?我们可以用数组来存储左、右、上能扩展到的最大距离,然后我们每次只处理每一行,然后对每一行求出左、上、右能扩展到的最大距离,最后求最大面积只需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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值