牛客多校训练第二场H. Second Large Rectangle (前缀和+单调栈)

题目传送门

题意

输入整数n和m(n和m均∈[1,1000]),给出一个n×m的01矩阵,求第二大全1矩阵的面积。(如果矩阵少于两个1,则输出0)

题解

单调栈做法:先预处理每个点(i,j)的高up[i][j],枚举每一行作为底边,遍历每一个点j,维护单调递减栈计算当前高度可达的最大区间(即当前可形成的全1矩阵的最大宽),宽×高即得当前可形成的全1矩形的面积,此时如果记录最大面积然后不断更新最优解即可求得最大全1矩阵面积。

但是题目要求的是第二大,所以本蒟蒻天真的认为只要把所有面积记录到一个数组,之后partial_sort排下序后输出第二大就OK了。too young too simple~

在经历过一次次WA之后去查了下,说是会存在第二大矩阵只包含在最大矩阵里面这种情况,奈何构造不出符合情况的测试用例来验证所以不太理解。最终去写了个生成随机测试用例,拿AC代码对拍了下,发现了如下两个测试用例存在错误。

6 6             2 24
100101   正确答案:5   101010001011100001001101     正确答案:5
011011   我的答案:4    110111111001001100010101      我的答案:4
111111
010100
011010
001110

所以要求第二大的矩阵面积,除了宽×高算面积外,还要再多算两种情况:(宽-1)×高,宽×(高-1)。

Code

/*133ms*/
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1005; int a[maxn][maxn],up[maxn][maxn],ans[3*maxn*maxn];//注意这里要3*maxn*maxn int main() { int n,m; while(~scanf("%d%d",&n,&m)){ memset(up,0,sizeof(up)); memset(a,0,sizeof(a)); memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%1d",&a[i][j]); up[i][j]=(a[i][j]==1)?up[i-1][j]+1:0; } } int area,q=0; for(int i=1;i<=n;i++){ stack<pair<int,int> >S; for(int j=1;j<=m+1;j++){ int L=j; while(!S.empty()&&up[i][j]<=S.top().first){ L=S.top().second; area=(j-L)*S.top().first; ans[q++]=area; area=(j-L-1)*S.top().first; ans[q++]=area; area=(j-L)*(S.top().first-1); ans[q++]=area; S.pop(); } if(S.empty()||up[i][j]>S.top().first) S.push({up[i][j],L}); } } partial_sort(ans,ans+2,ans+q,greater<int>()); cout<<ans[1]<<endl; } return 0; }




猜你喜欢

转载自www.cnblogs.com/HOLLAY/p/11355539.html