并不对劲的CF480E:Parking Lot

题目大意

有一个\(n\times m\)的网格,每个位置是黑色或者白色。\(k\)个操作,每个操作是将一个白格子染黑,操作后输出当前最大的白色正方形的边长。\(n,m,k\leq 2\times 10^3\)

题解

发现在每次操作是把白格子变黑,会使答案变小。维护“变小的最大值”听上去不太舒服。考虑把操作全都反过来,变成把黑格子染白。
这样每次操作之后,如果答案变大了,那么新的答案正方形一定包含在被操作的格子。
考虑对每个点记它左边最左的白格子和右边最右的白格子,操作时暴力更新与被操作点同行的点。
答案就是想找连续的一段与被操作的点在同一列,“段的长度”与“最左的右边界-最右的左边界”的最小值尽可能大。
发现可以判断答案是否大于一个数\(x\):当这一列上存在一个点,满足该点到从该点往上数第\(x\)个点满足“最左的右边界-最右的左边界”不少于\(x\)\(x\)就可以;反之就不可以。
可以用线段树或单调队列维护区间最左右边界和最右左边界。
这题知道判断解是否合法的方法后也不用二分,因为在处理过后答案就是不降的,而且不会超过\(min(n,m)\),而判断能否使答案增加1需要\(\Theta(n)\)\(\Theta(n\space log\space n)\)的时间复杂度,所以可以每次暴力判断能否使答案增加。
总时间复杂度\(\Theta(n\times m+k\times m+k\times n)\)

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 2007
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(int x)
{
	char ch[20];int f=0;
	if(!x){putchar('0'),putchar('\n');return;}
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
int qx[maxn],qy[maxn],q[maxn],hd,tl; 
int col[maxn][maxn],ans,lmx[maxn][maxn],rmx[maxn][maxn],n,m,k,res[maxn],tmp[maxn],dp[maxn][maxn];
char s[maxn];
int jud(int yy)
{
	hd=1,tl=0;
	rep(i,1,n)
	{
		while(hd<=tl&&q[hd]<i-(ans+1)+1)hd++;
		while(hd<=tl&&lmx[q[tl]][yy]<=lmx[i][yy])tl--;
		q[++tl]=i;
		if(i<ans+1)continue;
		tmp[i]=yy-lmx[q[hd]][yy]+1;
	}
	hd=1,tl=0;
	rep(i,1,n)
	{
		while(hd<=tl&&q[hd]<i-(ans+1)+1)hd++;
		while(hd<=tl&&rmx[q[tl]][yy]>=rmx[i][yy])tl--;
		q[++tl]=i;
		if(i<ans+1)continue;
		tmp[i]+=rmx[q[hd]][yy]-yy;
	}
	rep(i,ans+1,n)if(tmp[i]>=ans+1)return 1;
	return 0; 
}
int main()
{
	n=read(),m=read(),k=read();
	rep(i,1,n)
	{
		scanf("%s",s+1);
		rep(j,1,m)if(s[j]!='.')col[i][j]=1; 
	}
	rep(i,1,k)qx[i]=read(),qy[i]=read(),col[qx[i]][qy[i]]=1;
	rep(i,1,n)
	{
		rep(j,1,m)
		{
			if(col[i][j]){lmx[i][j]=j+1;continue;}
			dp[i][j]=min(min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
			ans=max(dp[i][j],ans);
			if(j==1||col[i][j-1])lmx[i][j]=j;
			else lmx[i][j]=lmx[i][j-1];
		}
		dwn(j,m,1)
		{
			if(col[i][j]){rmx[i][j]=j-1;continue;}
			if(j==m||col[i][j+1])rmx[i][j]=j;
			else rmx[i][j]=rmx[i][j+1];
		}
	}
	dwn(i,k,1)
	{
		res[i]=ans;
		col[qx[i]][qy[i]]=0;
		int nl=qy[i],nr=qy[i];
		while(nl-1>=1&&!col[qx[i]][nl-1])nl--;
		while(nr+1<=m&&!col[qx[i]][nr+1])nr++;
		rep(j,nl,nr)lmx[qx[i]][j]=nl,rmx[qx[i]][j]=nr;
		
		while(jud(qy[i]))ans++;
	}
	rep(i,1,k)write(res[i]);
	return (0-0);
}
posted @ 2019-10-07 18:51  echo6342  阅读(163)  评论(0编辑  收藏  举报