Loading

7305. 【2021.10.16NOIP提高组模拟】厜蓧篈壻鑨

Description

\(1\le n,m\le 1000\)

Solution

下面将 "#" 认为是 1,"." 认为是 0。

可以发现答案是具有二分性的。因此考虑二分答案。

对于答案 \(x\),先找出在 \(x\) 步内向外扩展不会到达的 0 的 1。

然后把这些点加入队列,然后 \(\text{bfs}\),看看经过 \(x\) 轮之后的形状是否与题目一样。

至于如何找出最先加入队列的 1,我们可以先预处理出每个 1 到 0 的距离,然后找那些距离大于 \(x\) 的 1。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
using namespace std;
int n,m,l,r,mid,ans,a[N][N],c[N][N],d[N*N][4];
int fx[5]={0,1,-1,0,0},fy[5]={0,0,0,1,-1};
bool b[N][N];
char ch;
bool check(int x)
{
	int h=0,t=0;
	memset(d,0,sizeof(d));
	memset(b,false,sizeof(b));
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
		{
			if (c[i][j]>x)
			{
				d[++t][1]=i;
				d[t][2]=j;
				d[t][3]=x;
				b[i][j]=true;
			}
		}
	while (h<=t)
	{
		int x=d[++h][1],y=d[h][2],z=d[h][3];
		for (int i=1;i<=4;++i)
		{
			int xx=x+fx[i],yy=y+fy[i];
			if (a[xx][yy]&&!b[xx][yy])
			{
				b[xx][yy]=true;
				if (z-1)
				{
					d[++t][1]=xx;
					d[t][2]=yy;
					d[t][3]=z-1;
				}
			}
		}
	}
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			if (a[i][j]&&!b[i][j]) return false;
	return true;
}
int main()
{
 	freopen("1ysa93e.in","r",stdin);
 	freopen("1ysa93e.out","w",stdout);
	scanf("%d%d",&n,&m);
	ch=getchar();
	for (int i=1;i<=n;++i)
	{
		while (ch!='.'&&ch!='#') ch=getchar();
		for (int j=1;j<=m;++j)
		{
			if (ch=='#') a[i][j]=1;
			ch=getchar();
		}
	}
	int h=0,t=1;
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			if (a[i][j]&&!(a[i][j-1]&&a[i][j+1]&&a[i-1][j]&&a[i+1][j])) c[i][j]=1,d[t][1]=i,d[t][2]=j,++t;
	while (h<=t)
	{
		int x=d[++h][1],y=d[h][2];
		for (int i=1;i<=4;++i)
		{
			int xx=x+fx[i],yy=y+fy[i];
			if (a[xx][yy]&&!c[xx][yy])
			{
				d[++t][1]=xx;
				d[t][2]=yy;
				c[xx][yy]=c[x][y]+1;
			}
		}
	}
	l=1;r=min(n,m);
	while (l<=r)
	{
		mid=(l+r)>>1;
		if (check(mid)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	printf("%d\n",ans);
	return 0;
} 
posted @ 2021-10-19 19:48  Thunder_S  阅读(137)  评论(0编辑  收藏  举报