UVaLive(LA) 3029 City Game,SEERC 2004题解

Vjudge传送门


题意:

这道题是要我们找出一个面积最大的子矩阵。然后让我们输出这个矩阵的面积乘3的结果(其实我不是特别明白为什么要乘三,乘三难道会让这道题的难度陡增???),然后矩阵描述是R和F,F表示是空地,R表示是障碍,只有是空地的地方才可以被划为子矩阵…
举个例子
F F F
F F R
R F F
的答案是2


题解:

显然我们这道题如果直接暴力的话,会非常难受,虽然我们可以维护01矩阵的二维前缀和,但即便是这样,也是非常难受的因为,n和m的范围是1000,而你维护了二维前缀和之后的时间至少是 n4 233
所以我们的做法其实很简单,维护一个 up[i][j] 数组,表示这个位置往下可以放多少个位置,也就是说往下可以数多少个空地,这个显然可以写出转移方程

up[i][j]=up[i1][j]+1

再维护一个 left[i][j] 数组(貌似只能维护 Left 数组,因为 left 好像冲突)
表示我们可以从这个点最多追溯到 左边的某个点
再维护一个 right[i][j] 数组( right 好像也冲突),所以我们用这个表示 i,j 这个位置最多可以追溯到右边的空地…举个例子
0123
1FFF
2FFR
3EFF
…垃圾latex没法对齐(显然是我不懂latex语法)
比如这个 Left[3][3]=2,RIght[3][2]=3
我们稍加思考(当然 ZBW 大佬可以不加思考,%%%)
可以发现如下转移方程
Left[i][j]=max(Left[i1][j],lo+1)

Right[i][j]=min(Right[i1][j],ro1)

其中 lo 表示现在扫这一行,扫到的最左边一个非空地的位置
同理 ro 表示现在扫的这一行,扫到的最右边一个非空地的位置

于是我们就可以开始愉快地进行递(动态)推(规划)啦


代码:

#include<cstdio>
#include<algorithm> 
using namespace std;        
const int MAXN=1000;
int mat[MAXN][MAXN],up[MAXN][MAXN],Left[MAXN][MAXN],Right[MAXN][MAXN];
int main(){int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&m,&n);
        for(register int i=0;i<m;i++){
            for(register int j=0;j<n;j++){
                int ch=getchar();while(ch!='F'&&ch!='R') ch=getchar();
                mat[i][j]=ch=='F'?0:1;
            }
        }
        int ans=0;
        for(register int i=0;i<m;i++){
            int lo=-1,ro=n;
            for(register int j=0;j<n;j++){
                if(mat[i][j]==1){
                    Left[i][j]=up[i][j]=0;lo=j;
                }else{
                    up[i][j]=i==0?1:up[i-1][j]+1;
                    Left[i][j]=i==0?lo+1:max(Left[i-1][j],lo+1);
                }
            }
            for(register int j=n-1;j>=0;j--){
                if(mat[i][j]==1){
                    Right[i][j]=n;ro=j;
                }else{
                    Right[i][j]=(i==0)?ro-1:min(Right[i-1][j],ro-1);
                    ans=max(ans,up[i][j]*(Right[i][j]-Left[i][j]+1));
                }
            }
        }
        printf("%d\n",ans*3);
    }
    return 0;
} 

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值