Live2d Test Env

HihoCoder1673 : 01间隔矩阵([Offer收割]编程练习赛41)(单调队列)

 

描述

给定一个N × M的01矩阵,小Hi希望从中找到一个01间隔的子矩阵,并且子矩阵的面积越大越好。

例如对于

0101010

1000101

0101010

1010101

0101010

在右侧有一个5 × 4的01间隔子矩阵,在下方有一个3 × 7的01间隔子矩阵。

输入

第一行包含两个整数N和M。  

以下N行M列包含一个N × M的01矩阵。  

对于30%的数据,1 ≤ N, M ≤ 250  

对于100%的数据,1 ≤ N, M ≤ 2000

输出

输出最大的01间隔子矩阵的面积。

样例输入

5 7  
0101010
1000101
0101010
1010101
0101010

样例输出

21
  • 模型:滑动窗口,最大广告牌面积
  • 手段:单调队列
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=2010;
char c[maxn][maxn];
int H[maxn][maxn],L[maxn][maxn],R[maxn][maxn],n,m,i,j,ans=0;;
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) scanf("%s",c[i]+1);
    
    for(i=1;i<=m;i++) H[1][i]=1;                 //得到h 
    for(i=1;i<=m;i++)
      for(j=2;j<=n;j++)
        H[j][i]=c[j][i]==c[j-1][i]?1:H[j-1][i]+1;
    
    for(i=1;i<=n;i++)                            //得到相应h的左延伸 
     for(j=1;j<=m;j++){
         if(j==1) { L[i][j]=1;continue;}//边界处理 
         int k=j;
         while(k>1&&c[i][k]!=c[i][k-1]&&H[i][k-1]>=H[i][j]) k=L[i][k-1]; 
         L[i][j]=k;
     }
     
    for(i=1;i<=n;i++)                             //得到相应h的右延伸 
     for(j=m;j>=1;j--){
         if(j==m) {R[i][j]=m;continue;}
         int k=j;
         while(k&&k<m&&c[i][k]!=c[i][k+1]&&H[i][k+1]>=H[i][j]) k=R[i][k+1]; 
         R[i][j]=k;
     } 
     
    for(i=1;i<=n;i++) 
     for(j=1;j<=m;j++)
        if((R[i][j]-L[i][j]+1)*H[i][j]>ans)  ans=(R[i][j]-L[i][j]+1)*H[i][j];
    
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2017-12-24 19:22  nimphy  阅读(493)  评论(0编辑  收藏  举报