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; }
It is your time to fight!