链接:https://ac.nowcoder.com/acm/contest/888/A
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
Gromah and LZR entered the great tomb, the first thing they see is a matrix of size n×mn\times mn×m, and the elements in the matrix are all 00_{}0 or 11_{}1.
LZR finds a note board saying "An all-one matrix is defined as the matrix whose elements are all 11_{}1, you should determine the number of all-one submatrices of the given matrix that are not completely included by any other all-one submatrices".
Meanwhile, Gromah also finds a password lock, obviously the password should be the number mentioned in the note board!
Please help them determine the password and enter the next level.
The first line contains two positive integers n,mn,m_{}n,m, denoting the size of given matrix.
Following nn_{}n lines each contains a string with length mm_{}m, whose elements are all 00_{}0 or 11_{}1, denoting the given matrix.
1≤n,m≤30001\le n,m \le 30001≤n,m≤3000
Print a non-negative integer, denoting the answer.
示例1
复制
3 4 0111 1110 0101
复制
5
The 5 matrices are (1,2)−(1,4), (1,2)−(2,3), (1,2)−(3,2), (2,1)−(2,3), (3,4)−(3,4)(1,2)-(1,4), \; (1,2)-(2,3), \; (1,2)-(3,2), \; (2,1)-(2,3), \; (3,4)-(3,4)_{}(1,2)−(1,4),(1,2)−(2,3),(1,2)−(3,2),(2,1)−(2,3),(3,4)−(3,4).
题目大意:给出了一个01矩阵,让求有多少个全一矩阵不被其他全1矩阵覆盖。
解题思路:预处理出每一个点向上连续的1是多少即h[i][j],即确定上边界。
我们依次枚举下边界第i行,对于当前点i,j h[i][j] 为上边界,然后用单调栈处理出 以上边界为最小值的左右边界L,R。
然后只需要判断一下,当前的下边界能不能向下延伸就可以了。注意对于第i行同一个子矩阵可能被多次计算(高度相同),
所以我们维护一个高度递减的单调栈就可以了。
#include
using namespace std;
const int N = 3005;
typedef long long ll;
const int mmax = 1e5+5;
char s[N][N];
int sum[N][N],L[N],R[N];
int h[N][N];
stackst;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)scanf("%s",s[i]+1);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(s[i][j]-'0')h[i][j] = h[i-1][j]+1;
sum[i][j] = sum[i][j-1] + s[i][j] - '0';
}
}
int ans=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
while(!st.empty() && h[i][j] <= h[i][st.top()]) st.pop();
if(st.empty()) L[j] = 1;
else L[j] = st.top()+1;
st.push(j);
}
while(!st.empty())st.pop();
for(int j=m; j>=1; j--)
{
while(!st.empty() && h[i][j] <= h[i][st.top()]) st.pop();
if(st.empty()) R[j] = m;
else R[j] = st.top()-1;
st.push(j);
}
while(!st.empty())st.pop();
for(int j=m; j>=1; j--)
{
if(h[i][j]==0)
{
while(!st.empty())st.pop();
continue;
}
while(!st.empty() && h[i][j] < h[i][st.top()]) st.pop();
if(st.empty() || h[i][j] != h[i][st.top()]) //避免高度相同的多次计算。
{
int l = L[j];
int r = R[j];
if(sum[i+1][r]-sum[i+1][l-1] != r - l + 1)ans++;
}
st.push(j);
}
while(!st.empty())st.pop();
}
cout<