题目大意

有一个\(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);
}

并不对劲的CF480E:Parking Lot的更多相关文章

  1. [CF480E]Parking Lot

    题意:给一个$n\times m$的网格,初始时有些地方不能选,给$k$个询问$(x,y)$,每次令$(x,y)$不能选,然后询问最大子正方形的边长 如果按原题来做,禁止选一个点对答案的影响是极其鬼畜 ...

  2. CF480E Parking Lot(单调队列+dp然鹅并不是优化)

    (全英文题面所以直接放化简题意) 题意:在一个二维平面内,初始有一些点,然后每个时间点加入一些点,对每个时间点求平面内最大的无障碍正方形 (这次的题目是真的神仙啊...) 首先,考虑暴力,如果对每一个 ...

  3. CF480E Parking Lot(two-pointers + 单调队列优化)

    题面 动态加障碍物,同时查询最大子正方形. n,m≤2000n,m\leq2000n,m≤2000 题解 加障碍不好做,直接离线后反着做,每次就是清除一个障碍物. 显然倒着做答案是递增的,而且答案的值 ...

  4. [LintCode] Parking Lot 停车场问题

    Design a parking lot. see CC150 OO Design for details.1) n levels, each level has m rows of spots an ...

  5. [CareerCup] 8.4 Parking Lot 停车场问题

    8.4 Design a parking lot using object-oriented principles. LintCode上的原题,请参见我的另一篇博客Parking Lot 停车场问题. ...

  6. Codeforces 46D Parking Lot

    传送门 D. Parking Lot time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  7. Codeforces Round #135 (Div. 2) E. Parking Lot 线段数区间合并

    E. Parking Lot time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  8. Amazon Interview Question: Design an OO parking lot

    Design an OO parking lot. What classes and functions will it have. It should say, full, empty and al ...

  9. HDOJ(HDU) 1673 Optimal Parking

    Problem Description When shopping on Long Street, Michael usually parks his car at some random locat ...

随机推荐

  1. 8.7 JSON存储数据方式(JavaScript对象表示法)

    8.7 JSON存储数据方式(JavaScript对象表示法) JSON JavaScript 对象表示法(JavaScript Object Notation) 是一种存储数据的方式. 一.创建JS ...

  2. ARTS打卡计划第九周

    Algorithms: https://leetcode-cn.com/problems/merge-two-sorted-lists/submissions/ 合并两个链表 Review:  “Pu ...

  3. 梯度提升树GBDT总结

    提升树的学习优化过程中,损失函数平方损失和指数损失时候,每一步优化相对简单,但对于一般损失函数优化的问题,Freidman提出了Gradient Boosting算法,其利用了损失函数的负梯度在当前模 ...

  4. ubuntu如何删除刚添加的源?

    答: sudo add-apt-repository -r <source_url> 如: sudo add-apt-repository -r ppa:linaro-maintainer ...

  5. LC 813. Largest Sum of Averages

    We partition a row of numbers A into at most K adjacent (non-empty) groups, then our score is the su ...

  6. [mybatis]传值和返回结果

    一.传值:parameterType的形式:可以传递一个类,也可以是一个map <update id="updateCategory" parameterType=" ...

  7. 分布式存储ceph--添加/删除osd(5)

    一.添加osd: 当前ceph集群中有如下osd,现在准备新添加osd:

  8. JAVA 基础编程练习题14 【程序 14 求日期】

    14 [程序 14 求日期] 题目:输入某年某月某日,判断这一天是这一年的第几天? 程序分析:以 3 月 5 日为例,应该先把前两个月的加起来,然后再加上 5 天即本年的第几天,特殊情况, 闰年且输入 ...

  9. git显示不出来图标标志

    git操作的文件夹,发现没有显示出来是否上传的绿色图标,这样导致不清楚哪些文件是否修改,是否上传. 以下方法让我的问题解决了,但我并不知道是不是所有人的问题都适用这种方法,如果你也遇到这种问题,可以尝 ...

  10. CWinThread类,使用后要不要使用CloseHandle释放内核

    在VC++中用AfxBeginThread()开启线程的时候,返回的是CWinThead类的指针.但是使用后是否应该用CloseHandle释放内核资源呢? 在<Windows核心编程>中 ...