CF370D Broken Monitor 题解

题意

一个 \(n \times m\) 的显示器,有的点是白色的,有的点是黑色的,求一个最小的正方形方框,使所有白点都在方框上。

分析

首先确定方框的边长,这个长度就是最左最右白块横坐标的差和最上最下白块纵坐标的差的最大值。如果边长比显示器长、宽的最小值大,那么不可能找到符合要求的方框。确定边长后,我们可以枚举每一个点作为左上角,检查这个方框上的白点数是否和总白点数相等。再加上前缀和优化即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e3+7;
inline void qread(){}template<class T1,class ...T2>
inline void qread(T1 &a,T2&... b)
{
	register T1 x=0;register bool f=false;char ch=getchar();
	while(ch<'0') f|=(ch=='-'),ch=getchar();
	while(ch>='0') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	x=(f?-x:x);a=x;qread(b...);
}
inline int qmax(const int &x,const int &y){return x>y?x:y;}
inline int qmin(const int &x,const int &y){return x<y?x:y;}
int n,m,sz,col[MAXN][MAXN],row[MAXN][MAXN],t=MAXN,b,l=MAXN,r,cnt;
// col是列的前缀和,row是行的前缀和
char a[MAXN][MAXN];
int main()
{
	qread(n,m);int i,j;for(i=1;i<=n;i++) scanf("%s",a[i]+1);
	for(i=1;i<=n;i++) for(j=1;j<=m;j++) if(a[i][j]=='w') t=qmin(t,i),b=qmax(b,i),l=qmin(l,j),r=qmax(r,j);
	sz=qmax(r-l,b-t); //计算边长
	if(!sz) //只有一个点
	{
		for(i=1;i<=n;i++) printf("%s\n",a[i]+1);
		return 0;
	}
	if(sz>=qmin(n,m)) return printf("-1\n"),0;
	for(i=1;i<=n;i++) 
	{
		for(j=1;j<=m;j++) 
		{
			col[j][i]=col[j][i-1]+(a[i][j]=='w'),row[i][j]=row[i][j-1]+(a[i][j]=='w');
			if(a[i][j]=='w') cnt++;
		}
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(i+sz>n||j+sz>m) continue;
			int t=row[i][j+sz]-row[i][j-1]+row[i+sz][j+sz]-row[i+sz][j-1]+col[j][i+sz-2]-col[j][i]+col[j+sz][i+sz-2]-col[j+sz][i]; //方框上的白点数
			if(t==cnt)
			{
				for(int ii=i;ii<=i+sz;ii++) if(a[ii][j]!='w') a[ii][j]='+'; //左边
				for(int ii=i;ii<=i+sz;ii++) if(a[ii][j+sz]!='w') a[ii][j+sz]='+'; //右边
				for(int jj=j;jj<=j+sz;jj++) if(a[i][jj]!='w') a[i][jj]='+'; //上边
				for(int jj=j;jj<=j+sz;jj++) if(a[i+sz][jj]!='w') a[i+sz][jj]='+'; //下边
				for(i=1;i<=n;i++) printf("%s\n",a[i]+1);
				return 0;
			}
		}
	}
	printf("-1\n");
	return 0;
}
posted @ 2022-02-17 20:43  l_x_y  阅读(25)  评论(0编辑  收藏  举报