cv1159 全0子矩阵 题解报告
【题目大意】
给定一个$n*n$的01矩阵,求一个全为0的子矩阵最多包含多少个0。
【思路分析】
其实据说是单调栈维护?但是我找到的题解说是用悬线法……
对于某一个位置$(i,j)$,求其往上最多能连续多少个0,往左最多能连续多少个0,往右最多能连续多少个0(往左和往右扩展时保证往上是合法的)
于是就over了?其实还是挺简单的……单独看某一行其实类似这题,然后如果要减小空间的话就滚动一下数组啦,只需要一维即可,但是因为我懒所以就直接用的二维数组。
【代码实现】
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define g() getchar() 7 #define rg register 8 #define go(i,a,b) for(rg int i=a;i<=b;i++) 9 #define back(i,a,b) for(rg int i=a;i>=b;i--) 10 #define db double 11 #define ll long long 12 #define il inline 13 #define pf printf 14 #define sf scanf 15 using namespace std; 16 int fr(){ 17 int w=0,q=1; 18 char ch=g(); 19 while(ch<'0'||ch>'9'){ 20 if(ch=='-') q=-1; 21 ch=g(); 22 } 23 while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g(); 24 return w*q; 25 } 26 const int N=2002; 27 int n,l[N][N],r[N][N],h[N][N],a[N][N],ans; 28 int main(){ 29 sf("%d",&n); 30 go(i,1,n) go(j,1,n) 31 sf("%d",&a[i][j]),l[i][j]=r[i][j]=h[i][j]=!a[i][j]; 32 //初始化,如果当前位置为1那么肯定是不合法的,如果为0那么在扩展之前要先加上自己 33 go(i,1,n) go(j,1,n) h[i][j]=a[i][j]==0?h[i-1][j]+1:0; 34 //当前位置为0则直接由正上方转移过来,否则不合法 35 go(i,1,n) go(j,1,n){//向左扩展 36 rg int k=j-1; 37 while(k>=1&&h[i][k]>=h[i][j]) l[i][j]++,k--; 38 } 39 go(i,1,n) back(j,n,1){//向右扩展(注意第二层循环的顺序) 40 rg int k=j+1; 41 while(k<=n&&h[i][k]>=h[i][j]) r[i][j]++,k++; 42 } 43 go(i,1,n) go(j,1,n)//统计答案 44 ans=max(ans,h[i][j]*(r[i][j]+l[i][j]-1)); 45 //减1是因为当前位置(i,j)记录了两次,所以计算宽度时要减去重复计算的一次 46 pf("%d\n",ans); 47 return 0; 48 }