2019 Bullock Summer Multi-School Training Camp (Eighth) A All-one Matrices [Dimension Reduction + Monotonic Stack + Prefix and]

Title description

Gromah and LZR entered the great tomb, the first thing they see is a matrix of size n×m, and the elements in the matrix are all 0 or 1.

LZR finds a note board saying "An all-one matrix is defined as the matrix whose elements are all 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.

Enter description

The first line contains two positive integers n,m​, denoting the size of given matrix.

Following n lines each contains a string with length m​, whose elements are all 0​ or 1​, denoting the given matrix.

1\leq n,m\leq 3000

Output description

Print a non-negative integer, denoting the answer.

Example input 

3 4
0111
1110
0101

Sample output 

5

Explanation 

The 5 matrices are (1,2)−(1,4),  (1,2)−(2,3),  (1,2)−(3,2),  (2,1)−(2,3),  (3,4)−(3,4)​.

The main idea:

There is an n * m 01 matrix, and it is required to find out how many largest all-one sub-matrices (that is, all elements of the sub-matrix are 1, and there is no other all-one sub-matrix that can completely contain this matrix).

analysis:

First, we need to reduce the dimension. For each row, record the number of consecutive 1s from each position upward, that is, expand the sub-matrix as much as possible.

Then, process each line in turn, first use the monotonically rising stack from left to right to find the farthest position where each position expands to the left, store it in L [j], and then use the monotone stack from right to left to find each position. The farthest position extended to the right is stored in R [j].

So far, the sub-matrix has been extended up, left, and right to the farthest position, and then the farthest downward expansion must be considered. Prefix may be recorded for each row and then for each matrix between L [j] and R [j], you can be O (1)found in a number of time between a lower level L [j] and R [j] 1 of So that you can decide whether you can expand downwards.

Finally, there is a problem. When traversing each row, L [j] and R [j] at different positions may represent the same matrix, so we must pay attention to deduplication.

See the code for specific explanation.

#include<bits/stdc++.h>

using namespace std;

const int maxn = 3e3+5;

int n,m,h[maxn][maxn],sum[maxn][maxn],q[maxn],R[maxn],L[maxn];

char s[maxn];

int main() {

    scanf("%d%d", &n, &m);
    
    memset(h,0,sizeof(h));

    for (int i = 1; i <= n; i++) {

        scanf("%s", s + 1);

        for (int j = 1; j <= m; j++) {

            if (s[j] == '1')

                h[i][j] = h[i - 1][j] + 1;

            sum[i][j] = sum[i][j - 1] + s[j] - '0';

        }

    }

    int ans = 0;
    
	//处理每一行 
    for (int i = n; i; i--) {

        stack<int> sta;

        sta.push(m + 1);

        //从右往左找出每个点j以h[i][j](向上连续1的高度)为高度的矩形右边界R[j]

        for (int j = m; j; j--) {

            while (!sta.empty() && h[i][j] <= h[i][sta.top()])

                sta.pop();

            if (sta.empty()) R[j] = m;//栈空,说明是当前最小的,则右边界为 m 

            else R[j] = sta.top() - 1;

            sta.push(j);

        }

        while (!sta.empty()) sta.pop();

        sta.push(0);

        //从左往右找出每个点j以h[i][j](向上连续1的高度)为高度的矩形左边界L[j]

        for (int j = 1; j <= m; j++) {

            while (!sta.empty() && h[i][j] <= h[i][sta.top()]) sta.pop();

            if (sta.empty()) L[j] = 1;//栈空,说明是当前最小的,则左边界为 1 

            else L[j] = sta.top() + 1;

            sta.push(j);

        }
        
        map<pair<int,pair<int,int>>,int> mp;//利用map去重,将每个矩阵包装为3元组(h[i][j],(L[j],R[j])) 

        for (int j = 1; j <= m; j++) {
        
        	int l=L[j];
        	
        	int r=R[j];
        	
        	if(h[i][j]==0)  continue;//h[i][j]=0,不可能形成矩阵 
        	
        	if(mp[make_pair(h[i][j],make_pair(L[j],R[j]))]==1)  continue;//这个子矩阵已经处理过 
        	
        	else{
        		if (sum[i + 1][r] - sum[i + 1][l - 1] != r - l + 1){//查看是否可以向下拓展,不能拓展则答案加一 
        			
        			ans++;
        			
        			mp[make_pair(h[i][j],make_pair(L[j],R[j]))]=1;
        			
//        			cout<<h[i][j]<<" "<<L[j]<<" "<<R[j]<<endl;
				}
			}

        }

    }

    printf("%d\n", ans);

    return 0;

}

 

Published 30 original articles · won 5 · 900 views

Guess you like

Origin blog.csdn.net/qq_42840665/article/details/99202355