2019 Bullock Summer Multi-School Training Camp (Octavo) Matrices todo en uno

Descripción del título

Gromah y LZR entraron en la gran tumba, lo primero que ven es una matriz de tamaño n × m, y los elementos en la matriz son todos 0 o 1.

LZR encuentra un tablero de notas que dice "Una matriz todo en uno se define como la matriz cuyos elementos son todos 1, debe determinar el número de submatrices todo en uno de la matriz dada que no están completamente incluidas por ninguna otra submatriz todo en uno ".

Mientras tanto, Gromah también encuentra un bloqueo de contraseña, ¡obviamente la contraseña debe ser el número mencionado en el tablero de notas!

Ayúdelos a determinar la contraseña e ingrese al siguiente nivel.

Ingrese la descripción

La primera línea contiene dos enteros positivos n, m, que denotan el tamaño de la matriz dada.

Siguiendo n líneas cada una contiene una cadena con longitud m, cuyos elementos son todos 0 o 1, que denotan la matriz dada.

1 \ leq n, m \ leq 3000

Descripción de salida

Imprima un número entero no negativo, que denota la respuesta.

Entrada de ejemplo 

3 4
0111
1110
0101

Salida de muestra 

5 5

Explicación 

Las 5 matrices son (1,2) - (1,4), (1,2) - (2,3), (1,2) - (3,2), (2,1) - (2,3 ), (3,4) - (3,4).

La idea principal:

Hay una matriz n * m 01, y es necesario averiguar cuántas submatrices unitarias más grandes (es decir, todos los elementos de la submatriz son 1, y no hay otra submatriz todo-uno que pueda contener completamente esta matriz).

Análisis:

Primero, necesitamos reducir la dimensión. Para cada fila, registre el número de 1s consecutivos desde cada posición hacia arriba, es decir, expanda la submatriz tanto como sea posible.

Luego, procese cada línea por turno, primero use la pila monotónicamente ascendente de izquierda a derecha para encontrar la posición más lejana donde cada posición se expande hacia la izquierda, guárdela en L [j], y luego use la pila monótona de derecha a izquierda para encontrar cada posición. La posición más lejana extendida a la derecha se almacena en R [j].

Hasta ahora, la submatriz se ha extendido hacia arriba, izquierda y derecha hasta la posición más lejana, y luego se debe considerar la expansión hacia abajo más lejana. Prefijo puede ser grabada para cada fila y luego para cada matriz entre L [j] y R [j], que se puede O (1)encontrar en una serie de tiempo entre un nivel inferior L [j] y R [j] 1 de Para que pueda decidir si puede expandirse hacia abajo.

Finalmente, hay un problema: al atravesar cada fila, L [j] y R [j] en diferentes posiciones pueden representar la misma matriz, por lo que debemos prestar atención a la deduplicación.

Vea el código para una explicación específica.

#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;

}

 

30 artículos originales publicados · ganó 5 · 900 visitas

Supongo que te gusta

Origin blog.csdn.net/qq_42840665/article/details/99202355
Recomendado
Clasificación