2020牛客暑期多校训练营(第九场) The Escape Plan of Groundhog

原题
题目描述
一堆桌子被排列成 N × M N×M 的矩形, a [ i ] [ j ] = 1 a[i][j]=1 表示位置 ( i j ) (i,j) 处有桌子,否则就没有。为了不被老师抓住,他要藏在一个矩形下,这个矩形要满足这些条件
1 1、 该子矩形的四条边上没有空位;
2 2、 子矩形中的空位与桌子的数量之差不超过 1 1 (不包括侧面的桌子)
3 3、 子矩形的长度和宽度必须大于 1 1
有多少个子矩形可以满足要求
输入描述
输入包含两个整数 N N M M ,范围为 [ 1 , 500 ] [1,500] ,中间用空格隔开。
然后是 N N 行,每行包含 M M 个字符来描述矩形 a [ i ] [ j ] 0 , 1 (a[i][j]∈{0,1})
样例1
输入

4 4
1 1 1 1
1 0 1 1
1 1 0 1
1 1 1 1

输出

3

说明

There're two 2*2 rectangle full of "1",and the whole 4*4 rectangle .

样例2
输入

5 5
1 0 1 1 1
1 0 1 0 1
1 1 0 1 1
1 0 0 1 1
1 1 1 1 1

输出

3

思路
因为本题的数据范围还是比较小的, N N M M 500 ≤500 ,所以可以考虑时间复杂度为 O ( O( n n 3 ) ) 的算法。
首先,我们会想到一种 O ( n O(n 4 ) ) 的算法
枚举矩阵左上的端点和右下的端点,然后判断一下矩阵周围一圈是不是 1 1 ,有一个不是 1 1 就退出搜索。然后判断一下矩阵除了最外圈的 1 1 0 0 1 1 数量的差值是否 0 ≤0 ,如果是,累加到 a n s ans 上。
显然这就是一个单纯的暴力,时间复杂度明显不对,所以还得优化。
首先,我们可以原来 01 01 的矩阵转化为 1 -1 1 1 的矩阵,然后求一下前缀和。
如果求出一个区间内的数字和的绝对值 1 ≤1 ,则表示这是一个合法的区间。
我们可以枚举上下行边界,对于每一列扫一遍,用前缀和维护即可,维护时不能算上这个矩阵周围的 1 1
枚举列的时候,如果这一列也是 1 1 ,就可以统计进去。
代码

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int inf=1<<15;
int a[505][505],b[505][505],c[250005],d[505],n,m,x=1;
int ans;
int main()
{
	d[0]=inf;scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){scanf("%lld",&a[i][j]);if(!a[i][j])a[i][j]=-1;b[i][j]=b[i-1][j]+a[i][j];}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++,x=1)
		{
			for(int k=1;k<=m;k++)
				if(a[i][k]^1||a[j][k]^1)
				{
					for(int l=x;l<=k;l++)if(b[j][l]-b[i-1][l]==j-i+1)c[d[l]]--;
					x=k+1,d[k]=inf;
				}
				else
				{
					if(b[j][k]-b[i-1][k]==j-i+1)ans+=c[d[k-1]]+c[d[k-1]+1]+c[d[k-1]-1];
	                d[k]=d[k-1]+b[j-1][k]-b[i][k];
	                if(b[j][k]-b[i-1][k]==j-i+1)c[d[k]]++;
				}
			for(int k=x;k<=m;k++)if(b[j][k]-b[i-1][k]==j-i+1)c[d[k]]--;
		}
	printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/bbbll123/article/details/107896136