- 题意:在一个01矩阵中找全为1且不为其他矩形完全覆盖的矩形的个数
- 思路:上下左右边界确定一个矩形。首先预处理01矩阵,例如:
3 4
0111
1110
0101
处理完为:
0 1 1 1
1 2 2 0
0 3 0 1
这个新得到的矩阵为(x,y)上面有多少连续的1
然后枚举每一行,对每一列用单调栈求矩形的左右边界,矩阵的上边界即是该点的大小,现在只需要判断这个矩形能不能向下延申,如果可以则说明他可以被另一个更大的矩形覆盖,判断能不能向下延申可以预处理每一行的前缀和,如果这行左右边界之间的和加上这一行左右边界之间的距离等于下一行左右边界之间的和 则说明可以向下延申。最后因为这样计算可能出现重复矩形,例如:
1 4
1111
这样的情况会求出4个矩形,所以需要去重,用map标记左右边界去重的化会超时,可以用单调栈来判断,维护一个单调递增的栈,每次判断,如果当前点的值等于栈顶的值则直接跳过不计算。
- 代码:
#include<bits/stdc++.h>
using namespace std;
//#define int long long
char g[3005][3005];
int e[3005][3005];
int sumr[3005][3005];//行
int n,m;
int l[3005],r[3005];
int init(int x,int y){
if(x<1) return 0;
if(g[x][y]=='1') e[x][y]=1;
init(x-1,y);
if(e[x][y]) e[x][y]+=e[x-1][y];
return e[x][y];
}
int ans=0;
void found(int x){
stack<int> s;
while(s.size()) s.pop();
for(int i=1;i<=m;i++){//左边界,单调增
while(s.size()&&e[x][s.top()]>=e[x][i]){
s.pop();
}
if(s.empty()) l[i]=1;
else l[i]=s.top()+1;
s.push(i);
}
while(!s.empty()) s.pop();
for(int i=m;i>=1;i--){
while(s.size()&&e[x][s.top()]>=e[x][i]) s.pop();
if(s.empty()) r[i]=m;
else r[i]=s.top()-1;
s.push(i);
}
// printf("\n");
// for(int i=1;i<=m;i++){
// printf("%d ",l[i]);
// }
// printf("\n");
// for(int j=1;j<=m;j++){
// printf("%d ",r[j]);
// }
//
// printf("\n");
while(s.size()) s.pop();
for(int i=1;i<=m;i++){
if(!e[x][i]) {
while(!s.empty()) s.pop();
continue;
}
while(s.size()&&e[x][i]<e[x][s.top()]) s.pop();//单调递增
if(!s.empty()&&e[x][s.top()]==e[x][i]) continue;
// printf("###%d %d %d\n",sumr[x][ r[i] ]-sumr[x][ l[i]-1 ],r[i]-l[i]+1,sumr[x+1][ r[i] ]-sumr[x+1][ l[i]-1 ]);
if(sumr[x][ r[i] ]-sumr[x][ l[i]-1 ]+ r[i]-l[i]+1 ==sumr[x+1][ r[i] ]-sumr[x+1][ l[i]-1 ]) continue;
ans++;
s.push(i);
}
// printf("%d\n",ans);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",g[i]+1);
}
for(int i=1;i<=m;i++){
init(n,i);
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=m;j++){
// printf("%d ",e[i][j]);
// }
// printf("\n");
// }
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
sumr[i][j]=sumr[i][j-1]+e[i][j];
}
}
for(int i=1;i<=n;i++)
found(i);
printf("%d\n",ans);
}